diff --git a/bookkeeper-benchmark/src/test/java/org/apache/bookkeeper/benchmark/TestBenchmark.java b/bookkeeper-benchmark/src/test/java/org/apache/bookkeeper/benchmark/TestBenchmark.java deleted file mode 100644 index 9813a97536f..00000000000 --- a/bookkeeper-benchmark/src/test/java/org/apache/bookkeeper/benchmark/TestBenchmark.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.benchmark; - -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test benchmarks. - */ -public class TestBenchmark extends BookKeeperClusterTestCase { - protected static final Logger LOG = LoggerFactory.getLogger(TestBenchmark.class); - - public TestBenchmark() { - super(5); - } - - @Before - public void setUp() throws Exception { - baseConf.setLedgerManagerFactoryClassName("org.apache.bookkeeper.meta.FlatLedgerManagerFactory"); - baseClientConf.setLedgerManagerFactoryClassName("org.apache.bookkeeper.meta.FlatLedgerManagerFactory"); - super.setUp(); - } - - @Override - protected String getMetadataServiceUri(String ledgersRootPath) { - return zkUtil.getMetadataServiceUri(ledgersRootPath, "flat"); - } - - @Test - public void testThroughputLatency() throws Exception { - String latencyFile = System.getProperty("test.latency.file", "latencyDump.dat"); - BenchThroughputLatency.main(new String[] { - "--zookeeper", zkUtil.getZooKeeperConnectString(), - "--time", "10", - "--skipwarmup", - "--throttle", "1", - "--sendlimit", "10000", - "--latencyFile", latencyFile - }); - } - - @Test - public void testBookie() throws Exception { - BookieSocketAddress bookie = serverByIndex(0).getLocalAddress(); - - BenchBookie.main(new String[] { - "--host", bookie.getSocketAddress().getHostName(), - "--port", String.valueOf(bookie.getPort()), - "--zookeeper", zkUtil.getZooKeeperConnectString(), - "--warmupCount", "10", - "--latencyCount", "100", - "--throughputCount", "100" - }); - } - - @Test - public void testReadThroughputLatency() throws Exception { - final AtomicBoolean threwException = new AtomicBoolean(false); - Thread t = new Thread() { - public void run() { - try { - BenchReadThroughputLatency.main(new String[] { - "--zookeeper", zkUtil.getZooKeeperConnectString(), - "--listen", "10"}); - } catch (Throwable t) { - LOG.error("Error reading", t); - threwException.set(true); - } - } - }; - t.start(); - - Thread.sleep(10000); - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'x'); - - long lastLedgerId = 0; - Assert.assertTrue("Thread should be running", t.isAlive()); - for (int i = 0; i < 10; i++) { - BookKeeper bk = new BookKeeper(zkUtil.getZooKeeperConnectString()); - LedgerHandle lh = bk.createLedger(BookKeeper.DigestType.CRC32, "benchPasswd".getBytes()); - lastLedgerId = lh.getId(); - try { - for (int j = 0; j < 100; j++) { - lh.addEntry(data); - } - } finally { - lh.close(); - bk.close(); - } - } - for (int i = 0; i < 60; i++) { - if (!t.isAlive()) { - break; - } - Thread.sleep(100); - } - - Assert.assertFalse("Thread should be finished", t.isAlive()); - - BenchReadThroughputLatency.main(new String[] { - "--zookeeper", zkUtil.getZooKeeperConnectString(), - "--ledger", String.valueOf(lastLedgerId)}); - } -} diff --git a/bookkeeper-common-allocator/src/test/java/org/apache/bookkeeper/common/allocator/impl/ByteBufAllocatorBuilderTest.java b/bookkeeper-common-allocator/src/test/java/org/apache/bookkeeper/common/allocator/impl/ByteBufAllocatorBuilderTest.java deleted file mode 100644 index 6f2538d6c81..00000000000 --- a/bookkeeper-common-allocator/src/test/java/org/apache/bookkeeper/common/allocator/impl/ByteBufAllocatorBuilderTest.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.allocator.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.util.ReferenceCountUtil; -import java.lang.reflect.Constructor; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.common.allocator.ByteBufAllocatorBuilder; -import org.apache.bookkeeper.common.allocator.OutOfMemoryPolicy; -import org.apache.bookkeeper.common.allocator.PoolingPolicy; -import org.junit.Test; - -/** - * Tests for {@link ByteBufAllocatorBuilderImpl}. - */ -public class ByteBufAllocatorBuilderTest { - - private static final OutOfMemoryError outOfDirectMemException; - - static { - try { - Class clazz = (Class) ByteBufAllocatorBuilderTest.class.getClassLoader() - .loadClass("io.netty.util.internal.OutOfDirectMemoryError"); - @SuppressWarnings("unchecked") - Constructor constructor = (Constructor) clazz - .getDeclaredConstructor(String.class); - - constructor.setAccessible(true); - outOfDirectMemException = constructor.newInstance("no mem"); - } catch (Exception e) { - throw new RuntimeException(e); - } - - } - - @Test - public void testOomWithException() { - ByteBufAllocator baseAlloc = mock(ByteBufAllocator.class); - when(baseAlloc.directBuffer(anyInt(), anyInt())).thenThrow(outOfDirectMemException); - - AtomicReference receivedException = new AtomicReference<>(); - - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .pooledAllocator(baseAlloc) - .outOfMemoryPolicy(OutOfMemoryPolicy.ThrowException) - .outOfMemoryListener((e) -> { - receivedException.set(e); - }) - .build(); - - try { - alloc.buffer(); - fail("Should have thrown exception"); - } catch (OutOfMemoryError e) { - // Expected - assertEquals(outOfDirectMemException, e); - } - - // Ensure the notification was triggered even when exception is thrown - assertEquals(outOfDirectMemException, receivedException.get()); - } - - @Test - public void testOomWithFallback() { - ByteBufAllocator baseAlloc = mock(ByteBufAllocator.class); - when(baseAlloc.directBuffer(anyInt(), anyInt())).thenThrow(outOfDirectMemException); - - AtomicReference receivedException = new AtomicReference<>(); - - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .pooledAllocator(baseAlloc) - .unpooledAllocator(UnpooledByteBufAllocator.DEFAULT) - .outOfMemoryPolicy(OutOfMemoryPolicy.FallbackToHeap) - .outOfMemoryListener((e) -> { - receivedException.set(e); - }) - .build(); - - // Should not throw exception - ByteBuf buf = alloc.buffer(); - assertEquals(UnpooledByteBufAllocator.DEFAULT, buf.alloc()); - - // No notification should have been triggered - assertEquals(null, receivedException.get()); - } - - @Test - public void testOomWithFallbackAndNoMoreHeap() { - ByteBufAllocator baseAlloc = mock(ByteBufAllocator.class); - when(baseAlloc.directBuffer(anyInt(), anyInt())).thenThrow(outOfDirectMemException); - - ByteBufAllocator heapAlloc = mock(ByteBufAllocator.class); - OutOfMemoryError noHeapError = new OutOfMemoryError("no more heap"); - when(heapAlloc.heapBuffer(anyInt(), anyInt())).thenThrow(noHeapError); - - AtomicReference receivedException = new AtomicReference<>(); - - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .pooledAllocator(baseAlloc) - .unpooledAllocator(heapAlloc) - .outOfMemoryPolicy(OutOfMemoryPolicy.FallbackToHeap) - .outOfMemoryListener((e) -> { - receivedException.set(e); - }) - .build(); - - try { - alloc.buffer(); - fail("Should have thrown exception"); - } catch (OutOfMemoryError e) { - // Expected - assertEquals(noHeapError, e); - } - - // Ensure the notification was triggered even when exception is thrown - assertEquals(noHeapError, receivedException.get()); - } - - @Test - public void testOomUnpooledDirect() { - ByteBufAllocator heapAlloc = mock(ByteBufAllocator.class); - OutOfMemoryError noMemError = new OutOfMemoryError("no more direct mem"); - when(heapAlloc.directBuffer(anyInt(), anyInt())).thenThrow(noMemError); - - AtomicReference receivedException = new AtomicReference<>(); - - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .poolingPolicy(PoolingPolicy.UnpooledHeap) - .unpooledAllocator(heapAlloc) - .outOfMemoryPolicy(OutOfMemoryPolicy.FallbackToHeap) - .outOfMemoryListener((e) -> { - receivedException.set(e); - }) - .build(); - - try { - alloc.directBuffer(); - fail("Should have thrown exception"); - } catch (OutOfMemoryError e) { - // Expected - assertEquals(noMemError, e); - } - - // Ensure the notification was triggered even when exception is thrown - assertEquals(noMemError, receivedException.get()); - } - - @Test - public void testOomUnpooledWithHeap() { - ByteBufAllocator heapAlloc = mock(ByteBufAllocator.class); - OutOfMemoryError noHeapError = new OutOfMemoryError("no more heap"); - when(heapAlloc.heapBuffer(anyInt(), anyInt())).thenThrow(noHeapError); - - AtomicReference receivedException = new AtomicReference<>(); - - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .poolingPolicy(PoolingPolicy.UnpooledHeap) - .unpooledAllocator(heapAlloc) - .outOfMemoryPolicy(OutOfMemoryPolicy.FallbackToHeap) - .outOfMemoryListener((e) -> { - receivedException.set(e); - }) - .build(); - - try { - alloc.heapBuffer(); - fail("Should have thrown exception"); - } catch (OutOfMemoryError e) { - // Expected - assertEquals(noHeapError, e); - } - - // Ensure the notification was triggered even when exception is thrown - assertEquals(noHeapError, receivedException.get()); - } - - @Test - public void testUnpooled() { - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .poolingPolicy(PoolingPolicy.UnpooledHeap) - .build(); - - ByteBuf buf = alloc.buffer(); - assertEquals(UnpooledByteBufAllocator.DEFAULT, buf.alloc()); - assertTrue(buf.hasArray()); - - ByteBuf buf2 = alloc.directBuffer(); - assertEquals(UnpooledByteBufAllocator.DEFAULT, buf2.alloc()); - assertFalse(buf2.hasArray()); - } - - @Test - public void testPooled() { - PooledByteBufAllocator pooledAlloc = new PooledByteBufAllocator(true); - - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .poolingPolicy(PoolingPolicy.PooledDirect) - .pooledAllocator(pooledAlloc) - .build(); - - assertTrue(alloc.isDirectBufferPooled()); - - ByteBuf buf1 = alloc.buffer(); - assertEquals(pooledAlloc, buf1.alloc()); - assertFalse(buf1.hasArray()); - ReferenceCountUtil.release(buf1); - - ByteBuf buf2 = alloc.directBuffer(); - assertEquals(pooledAlloc, buf2.alloc()); - assertFalse(buf2.hasArray()); - ReferenceCountUtil.release(buf2); - - ByteBuf buf3 = alloc.heapBuffer(); - assertEquals(pooledAlloc, buf3.alloc()); - assertTrue(buf3.hasArray()); - ReferenceCountUtil.release(buf3); - } - - @Test - public void testPooledWithDefaultAllocator() { - ByteBufAllocator alloc = ByteBufAllocatorBuilder.create() - .poolingPolicy(PoolingPolicy.PooledDirect) - .poolingConcurrency(3) - .build(); - - assertTrue(alloc.isDirectBufferPooled()); - - ByteBuf buf1 = alloc.buffer(); - assertEquals(PooledByteBufAllocator.class, buf1.alloc().getClass()); - assertEquals(3, ((PooledByteBufAllocator) buf1.alloc()).metric().numDirectArenas()); - assertFalse(buf1.hasArray()); - ReferenceCountUtil.release(buf1); - - ByteBuf buf2 = alloc.directBuffer(); - assertFalse(buf2.hasArray()); - ReferenceCountUtil.release(buf2); - - ByteBuf buf3 = alloc.heapBuffer(); - assertTrue(buf3.hasArray()); - ReferenceCountUtil.release(buf3); - } -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BatchedArrayBlockingQueueTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BatchedArrayBlockingQueueTest.java deleted file mode 100644 index 20e2f3723f3..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BatchedArrayBlockingQueueTest.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.common.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.junit.Test; - -/** - * Test the growable array blocking queue. - */ -public class BatchedArrayBlockingQueueTest { - - @Test - public void simple() throws Exception { - BlockingQueue queue = new BatchedArrayBlockingQueue<>(4); - - assertEquals(null, queue.poll()); - - assertEquals(4, queue.remainingCapacity()); - - try { - queue.element(); - fail("Should have thrown exception"); - } catch (NoSuchElementException e) { - // Expected - } - - try { - queue.iterator(); - fail("Should have thrown exception"); - } catch (UnsupportedOperationException e) { - // Expected - } - - // Test index rollover - for (int i = 0; i < 100; i++) { - queue.add(i); - - assertEquals(i, queue.take().intValue()); - } - - queue.offer(1); - queue.offer(2); - queue.offer(3); - queue.offer(4); - - assertEquals(4, queue.size()); - - List list = new ArrayList<>(); - queue.drainTo(list, 3); - - assertEquals(1, queue.size()); - assertEquals(Lists.newArrayList(1, 2, 3), list); - assertEquals(4, queue.peek().intValue()); - - assertEquals(4, queue.element().intValue()); - assertEquals(4, queue.remove().intValue()); - try { - queue.remove(); - fail("Should have thrown exception"); - } catch (NoSuchElementException e) { - // Expected - } - } - - @Test - public void blockingTake() throws Exception { - BlockingQueue queue = new GrowableMpScArrayConsumerBlockingQueue<>(); - - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - int expected = 0; - - for (int i = 0; i < 100; i++) { - int n = queue.take(); - - assertEquals(expected++, n); - } - - latch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - - int n = 0; - for (int i = 0; i < 10; i++) { - for (int j = 0; j < 10; j++) { - queue.put(n); - ++n; - } - - // Wait until all the entries are consumed - while (!queue.isEmpty()) { - Thread.sleep(1); - } - } - - latch.await(); - } - - @Test - public void blockWhenFull() throws Exception { - BlockingQueue queue = new BatchedArrayBlockingQueue<>(4); - - assertEquals(null, queue.poll()); - - assertTrue(queue.offer(1)); - assertTrue(queue.offer(2)); - assertTrue(queue.offer(3)); - assertTrue(queue.offer(4)); - assertFalse(queue.offer(5)); - - assertEquals(4, queue.size()); - - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - queue.put(5); - latch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - - Thread.sleep(100); - assertEquals(1, latch.getCount()); - - assertEquals(1, (int) queue.poll()); - - assertTrue(latch.await(1, TimeUnit.SECONDS)); - assertEquals(4, queue.size()); - - - queue.clear(); - assertEquals(0, queue.size()); - - assertTrue(queue.offer(1, 1, TimeUnit.SECONDS)); - assertTrue(queue.offer(2, 1, TimeUnit.SECONDS)); - assertTrue(queue.offer(3, 1, TimeUnit.SECONDS)); - assertEquals(3, queue.size()); - - List list = new ArrayList<>(); - queue.drainTo(list); - assertEquals(0, queue.size()); - - assertEquals(Lists.newArrayList(1, 2, 3), list); - } - - @Test - public void pollTimeout() throws Exception { - BlockingQueue queue = new BatchedArrayBlockingQueue<>(4); - - assertEquals(null, queue.poll(1, TimeUnit.MILLISECONDS)); - - queue.put(1); - assertEquals(1, queue.poll(1, TimeUnit.MILLISECONDS).intValue()); - - // 0 timeout should not block - assertEquals(null, queue.poll(0, TimeUnit.HOURS)); - - queue.put(2); - queue.put(3); - assertEquals(2, queue.poll(1, TimeUnit.HOURS).intValue()); - assertEquals(3, queue.poll(1, TimeUnit.HOURS).intValue()); - } - - @Test - public void pollTimeout2() throws Exception { - BlockingQueue queue = new BatchedArrayBlockingQueue<>(10); - - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - queue.poll(1, TimeUnit.HOURS); - - latch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - - // Make sure background thread is waiting on poll - Thread.sleep(100); - queue.put(1); - - latch.await(); - } - - - @Test - public void drainToArray() throws Exception { - BatchedArrayBlockingQueue queue = new BatchedArrayBlockingQueue<>(100); - - for (int i = 0; i < 10; i++) { - queue.add(i); - } - - Integer[] local = new Integer[5]; - int items = queue.takeAll(local); - assertEquals(5, items); - for (int i = 0; i < items; i++) { - assertEquals(i, (int) local[i]); - } - - assertEquals(5, queue.size()); - - items = queue.takeAll(local); - assertEquals(5, items); - for (int i = 0; i < items; i++) { - assertEquals(i + 5, (int) local[i]); - } - - assertEquals(0, queue.size()); - - /// Block when empty - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - int c = queue.takeAll(local); - assertEquals(1, c); - latch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - - Thread.sleep(100); - assertEquals(1, latch.getCount()); - - assertEquals(0, queue.size()); - - // Unblock the drain - queue.put(1); - - assertTrue(latch.await(1, TimeUnit.SECONDS)); - assertEquals(0, queue.size()); - } - - @Test - public void putAll() throws Exception { - BatchedArrayBlockingQueue queue = new BatchedArrayBlockingQueue<>(10); - - Integer[] items = new Integer[100]; - for (int i = 0; i < 100; i++) { - items[i] = i; - } - - queue.putAll(items, 0, 5); - assertEquals(5, queue.size()); - queue.putAll(items, 0, 5); - assertEquals(10, queue.size()); - - queue.clear(); - - /// Block when empty - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - queue.putAll(items, 0, 11); - latch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - - Thread.sleep(100); - assertEquals(1, latch.getCount()); - assertEquals(10, queue.size()); - - // Unblock the putAll - queue.take(); - - assertTrue(latch.await(1, TimeUnit.SECONDS)); - assertEquals(10, queue.size()); - } -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BlockingMpscQueueTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BlockingMpscQueueTest.java deleted file mode 100644 index f37c6cca341..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BlockingMpscQueueTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; -import org.junit.Test; - -/** - * Unit tests for {@link BlockingMpscQueue}. - */ -public class BlockingMpscQueueTest { - - @Test - public void basicTest() throws Exception { - final int size = 15; - BlockingQueue queue = new BlockingMpscQueue<>(size); - - for (int i = 0; i < size; i++) { - queue.put(i); - - assertEquals(size - i, queue.remainingCapacity()); - } - - assertEquals(size, queue.size()); - - for (int i = 0; i < size; i++) { - Integer n = queue.take(); - assertTrue(n != null); - } - - assertEquals(0, queue.size()); - - Integer res = queue.poll(100, TimeUnit.MILLISECONDS); - assertNull(res); - } - - @Test - public void testOffer() throws Exception { - final int size = 16; - BlockingQueue queue = new BlockingMpscQueue<>(size); - - for (int i = 0; i < size; i++) { - assertTrue(queue.offer(1, 100, TimeUnit.MILLISECONDS)); - } - - assertEquals(size, queue.size()); - - assertFalse(queue.offer(1, 100, TimeUnit.MILLISECONDS)); - assertEquals(size, queue.size()); - } - - @Test - public void testDrain() throws Exception { - final int size = 10; - BlockingQueue queue = new BlockingMpscQueue<>(size); - - for (int i = 0; i < size; i++) { - queue.put(i); - } - - List list = new ArrayList<>(size); - queue.drainTo(list); - - assertEquals(size, list.size()); - - assertEquals(0, queue.size()); - - Integer res = queue.poll(100, TimeUnit.MILLISECONDS); - assertNull(res); - } - - @Test - public void testDrainWithLimit() throws Exception { - final int size = 10; - BlockingQueue queue = new BlockingMpscQueue<>(size); - - for (int i = 0; i < size; i++) { - queue.put(i); - } - - List list = new ArrayList<>(); - queue.drainTo(list, 5); - assertEquals(5, list.size()); - - assertEquals(5, queue.size()); - } -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/GrowableArrayBlockingQueueTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/GrowableArrayBlockingQueueTest.java deleted file mode 100644 index 7b20294d581..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/GrowableArrayBlockingQueueTest.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.common.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import org.junit.Test; - -/** - * Test the growable array blocking queue. - */ -public class GrowableArrayBlockingQueueTest { - - @Test - public void simple() throws Exception { - BlockingQueue queue = new GrowableMpScArrayConsumerBlockingQueue<>(4); - - assertEquals(null, queue.poll()); - - assertEquals(Integer.MAX_VALUE, queue.remainingCapacity()); - assertEquals("[]", queue.toString()); - - try { - queue.element(); - fail("Should have thrown exception"); - } catch (NoSuchElementException e) { - // Expected - } - - try { - queue.iterator(); - fail("Should have thrown exception"); - } catch (UnsupportedOperationException e) { - // Expected - } - - // Test index rollover - for (int i = 0; i < 100; i++) { - queue.add(i); - - assertEquals(i, queue.take().intValue()); - } - - queue.offer(1); - assertEquals("[1]", queue.toString()); - queue.offer(2); - assertEquals("[1, 2]", queue.toString()); - queue.offer(3); - assertEquals("[1, 2, 3]", queue.toString()); - queue.offer(4); - assertEquals("[1, 2, 3, 4]", queue.toString()); - - assertEquals(4, queue.size()); - - List list = new ArrayList<>(); - queue.drainTo(list, 3); - - assertEquals(1, queue.size()); - assertEquals(Lists.newArrayList(1, 2, 3), list); - assertEquals("[4]", queue.toString()); - assertEquals(4, queue.peek().intValue()); - - assertEquals(4, queue.element().intValue()); - assertEquals(4, queue.remove().intValue()); - try { - queue.remove(); - fail("Should have thrown exception"); - } catch (NoSuchElementException e) { - // Expected - } - } - - @Test - public void blockingTake() throws Exception { - BlockingQueue queue = new GrowableMpScArrayConsumerBlockingQueue<>(); - - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - int expected = 0; - - for (int i = 0; i < 100; i++) { - int n = queue.take(); - - assertEquals(expected++, n); - } - - latch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - - int n = 0; - for (int i = 0; i < 10; i++) { - for (int j = 0; j < 10; j++) { - queue.put(n); - ++n; - } - - // Wait until all the entries are consumed - while (!queue.isEmpty()) { - Thread.sleep(1); - } - } - - latch.await(); - } - - @Test - public void growArray() throws Exception { - BlockingQueue queue = new GrowableMpScArrayConsumerBlockingQueue<>(4); - - assertEquals(null, queue.poll()); - - assertTrue(queue.offer(1)); - assertTrue(queue.offer(2)); - assertTrue(queue.offer(3)); - assertTrue(queue.offer(4)); - assertTrue(queue.offer(5)); - - assertEquals(5, queue.size()); - - queue.clear(); - assertEquals(0, queue.size()); - - assertTrue(queue.offer(1, 1, TimeUnit.SECONDS)); - assertTrue(queue.offer(2, 1, TimeUnit.SECONDS)); - assertTrue(queue.offer(3, 1, TimeUnit.SECONDS)); - assertEquals(3, queue.size()); - - List list = new ArrayList<>(); - queue.drainTo(list); - assertEquals(0, queue.size()); - - assertEquals(Lists.newArrayList(1, 2, 3), list); - } - - @Test - public void pollTimeout() throws Exception { - BlockingQueue queue = new GrowableMpScArrayConsumerBlockingQueue<>(4); - - assertEquals(null, queue.poll(1, TimeUnit.MILLISECONDS)); - - queue.put(1); - assertEquals(1, queue.poll(1, TimeUnit.MILLISECONDS).intValue()); - - // 0 timeout should not block - assertEquals(null, queue.poll(0, TimeUnit.HOURS)); - - queue.put(2); - queue.put(3); - assertEquals(2, queue.poll(1, TimeUnit.HOURS).intValue()); - assertEquals(3, queue.poll(1, TimeUnit.HOURS).intValue()); - } - - @Test - public void pollTimeout2() throws Exception { - BlockingQueue queue = new GrowableMpScArrayConsumerBlockingQueue<>(); - - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - queue.poll(1, TimeUnit.HOURS); - - latch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - - // Make sure background thread is waiting on poll - Thread.sleep(100); - queue.put(1); - - latch.await(); - } - - - static class TestThread extends Thread { - - private volatile boolean stop; - private final BlockingQueue readQ; - private final BlockingQueue writeQ; - - private final AtomicLong counter = new AtomicLong(); - - TestThread(BlockingQueue readQ, BlockingQueue writeQ) { - this.readQ = readQ; - this.writeQ = writeQ; - } - - @Override - public void run() { - ArrayList localQ = new ArrayList<>(); - - while (!stop) { - int items = readQ.drainTo(localQ); - if (items > 0) { - for (int i = 0; i < items; i++) { - writeQ.add(localQ.get(i)); - } - - counter.addAndGet(items); - localQ.clear(); - } else { - try { - writeQ.add(readQ.take()); - counter.incrementAndGet(); - } catch (InterruptedException e) { - return; - } - } - } - } - } - - public static void main(String[] args) throws Exception { - int n = 10_000; - BlockingQueue q1 = new GrowableMpScArrayConsumerBlockingQueue<>(); - BlockingQueue q2 = new GrowableMpScArrayConsumerBlockingQueue<>(); -// BlockingQueue q1 = new ArrayBlockingQueue<>(N * 2); -// BlockingQueue q2 = new ArrayBlockingQueue<>(N * 2); -// BlockingQueue q1 = new LinkedBlockingQueue<>(); -// BlockingQueue q2 = new LinkedBlockingDeque<>(); - - TestThread t1 = new TestThread(q1, q2); - TestThread t2 = new TestThread(q2, q1); - - for (int i = 0; i < n; i++) { - q1.add(i); - } - - t1.start(); - t2.start(); - - Thread.sleep(10_000); - - System.out.println("Throughput " + (t1.counter.get() / 10 / 1e6) + " Millions items/s"); - t1.stop = true; - t2.stop = true; - } -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/RecyclableArrayListTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/RecyclableArrayListTest.java deleted file mode 100644 index 9037d219342..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/RecyclableArrayListTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.collections; - -import static org.junit.Assert.assertEquals; - -import org.apache.bookkeeper.common.collections.RecyclableArrayList.Recycler; -import org.junit.Test; - -/** - * Unit test of {@link RecyclableArrayList}. - */ -public class RecyclableArrayListTest { - - private final Recycler recycler; - - public RecyclableArrayListTest() { - this.recycler = new Recycler<>(); - } - - @Test - public void testRecycle() { - RecyclableArrayList array = recycler.newInstance(); - for (int i = 0; i < 5; i++) { - array.add(i); - } - assertEquals(5, array.size()); - array.recycle(); - assertEquals(0, array.size()); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestComponentStarter.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestComponentStarter.java deleted file mode 100644 index ef35a9d7b39..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestComponentStarter.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.component; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.lang.Thread.UncaughtExceptionHandler; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.common.component.ComponentStarter.ComponentShutdownHook; -import org.junit.Test; - -/** - * Test Case of {@link ComponentStarter}. - */ -public class TestComponentStarter { - - @Test - public void testStartComponent() { - LifecycleComponent component = mock(LifecycleComponent.class); - when(component.getName()).thenReturn("test-start-component"); - ComponentStarter.startComponent(component); - verify(component).publishInfo(any(ComponentInfoPublisher.class)); - verify(component).start(); - } - - @Test - public void testComponentShutdownHook() throws Exception { - LifecycleComponent component = mock(LifecycleComponent.class); - when(component.getName()).thenReturn("test-shutdown-hook"); - CompletableFuture future = new CompletableFuture<>(); - ComponentShutdownHook shutdownHook = new ComponentShutdownHook(component, future); - shutdownHook.run(); - verify(component).close(); - future.get(); - } - - @Test - public void testExceptionHandler() throws Exception { - // prepare a mock lifecycle component - LifecycleComponent component = mock(LifecycleComponent.class); - when(component.getName()).thenReturn("test-exception-handler"); - AtomicReference exceptionHandlerRef = new AtomicReference<>(); - doAnswer(invocationOnMock -> { - UncaughtExceptionHandler handler = invocationOnMock.getArgument(0); - exceptionHandlerRef.set(handler); - return null; - }).when(component).setExceptionHandler(any(UncaughtExceptionHandler.class)); - - // start the future - CompletableFuture startFuture = ComponentStarter.startComponent(component); - verify(component, times(1)).start(); - verify(component, times(1)).setExceptionHandler(eq(exceptionHandlerRef.get())); - - // if an exception is signaled through exception handler, - // the startFuture will be completed and the component will be shutdown - exceptionHandlerRef.get().uncaughtException( - Thread.currentThread(), new Exception("test-exception-handler")); - - startFuture.get(); - verify(component, times(1)).close(); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestLifecycleComponentStack.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestLifecycleComponentStack.java deleted file mode 100644 index de575ae55d5..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestLifecycleComponentStack.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.component; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.lang.Thread.UncaughtExceptionHandler; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; - -/** - * Unit test for {@link LifecycleComponentStack}. - */ -public class TestLifecycleComponentStack { - - @Test(expected = NullPointerException.class) - public void testBuilderWithNullName() { - LifecycleComponentStack.newBuilder().withName(null).build(); - } - - @Test(expected = NullPointerException.class) - public void testBuilderWithNullComponent() { - LifecycleComponentStack.newBuilder().addComponent(null); - } - - @Test(expected = IllegalArgumentException.class) - public void testBuilderWithEmptyComponentList() { - LifecycleComponentStack.newBuilder().withName("empty-list").build(); - } - - @Test - public void testGetName() { - String name = "test-get-name"; - LifecycleComponentStack stack = LifecycleComponentStack.newBuilder() - .withName(name) - .addComponent(mock(LifecycleComponent.class)) - .build(); - assertEquals(name, stack.getName()); - } - - @Test - public void testLifecycleState() { - LifecycleComponent component1 = mock(LifecycleComponent.class); - when(component1.lifecycleState()).thenReturn(Lifecycle.State.INITIALIZED); - LifecycleComponent component2 = mock(LifecycleComponent.class); - when(component2.lifecycleState()).thenReturn(Lifecycle.State.STARTED); - - LifecycleComponentStack stack = LifecycleComponentStack.newBuilder() - .withName("get-lifecycle-state") - .addComponent(component1) - .addComponent(component2) - .build(); - - assertEquals(Lifecycle.State.INITIALIZED, stack.lifecycleState()); - } - - @Test - public void testAddRemoveLifecycleListener() { - LifecycleComponent component1 = mock(LifecycleComponent.class); - LifecycleComponent component2 = mock(LifecycleComponent.class); - - LifecycleComponentStack stack = LifecycleComponentStack.newBuilder() - .withName("get-lifecycle-listener") - .addComponent(component1) - .addComponent(component2) - .build(); - - LifecycleListener listener = mock(LifecycleListener.class); - stack.addLifecycleListener(listener); - verify(component1).addLifecycleListener(listener); - verify(component2).addLifecycleListener(listener); - stack.removeLifecycleListener(listener); - verify(component1).removeLifecycleListener(listener); - verify(component2).removeLifecycleListener(listener); - } - - @Test - public void testStartStopClose() { - LifecycleComponent component1 = mock(LifecycleComponent.class); - LifecycleComponent component2 = mock(LifecycleComponent.class); - - LifecycleComponentStack stack = LifecycleComponentStack.newBuilder() - .withName("get-lifecycle-listener") - .addComponent(component1) - .addComponent(component2) - .build(); - - stack.start(); - verify(component1).start(); - verify(component2).start(); - stack.stop(); - verify(component1).stop(); - verify(component2).stop(); - stack.close(); - verify(component1).close(); - verify(component2).close(); - } - - @Test - public void testSetExceptionHandler() { - LifecycleComponent component1 = mock(LifecycleComponent.class); - LifecycleComponent component2 = mock(LifecycleComponent.class); - - LifecycleComponentStack stack = LifecycleComponentStack.newBuilder() - .withName("set-exception-handler-stack") - .addComponent(component1) - .addComponent(component2) - .build(); - - UncaughtExceptionHandler handler = mock(UncaughtExceptionHandler.class); - - stack.setExceptionHandler(handler); - verify(component1, times(1)).setExceptionHandler(eq(handler)); - verify(component2, times(1)).setExceptionHandler(eq(handler)); - } - - @Test - public void testExceptionHandlerShutdownLifecycleComponentStack() throws Exception { - LifecycleComponent component1 = mock(LifecycleComponent.class); - LifecycleComponent component2 = mock(LifecycleComponent.class); - AtomicReference handlerRef1 = new AtomicReference<>(); - doAnswer(invocationOnMock -> { - handlerRef1.set(invocationOnMock.getArgument(0)); - return null; - }).when(component1).setExceptionHandler(any(UncaughtExceptionHandler.class)); - - LifecycleComponentStack stack = LifecycleComponentStack.newBuilder() - .withName("exception-handler-shutdown-lifecycle-component-stack") - .addComponent(component1) - .addComponent(component2) - .build(); - - CompletableFuture startFuture = ComponentStarter.startComponent(stack); - verify(component1, times(1)).start(); - verify(component1, times(1)).setExceptionHandler(eq(handlerRef1.get())); - verify(component2, times(1)).start(); - verify(component2, times(1)).setExceptionHandler(eq(handlerRef1.get())); - - // if an exception is signaled through any component, - // the startFuture will be completed and all the components will be shutdown - handlerRef1.get().uncaughtException( - Thread.currentThread(), new Exception("exception-handler-shutdown-lifecycle-component-stack")); - - startFuture.get(); - verify(component1, times(1)).close(); - verify(component2, times(1)).close(); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/concurrent/TestFutureUtils.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/concurrent/TestFutureUtils.java deleted file mode 100644 index 4a347f38440..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/concurrent/TestFutureUtils.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.concurrent; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.base.Stopwatch; -import com.google.common.collect.Lists; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Function; -import java.util.stream.LongStream; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.junit.Test; - -/** - * Unit Test for {@link FutureUtils}. - */ -public class TestFutureUtils { - - /** - * Test Exception. - */ - static class TestException extends IOException { - private static final long serialVersionUID = -6256482498453846308L; - - public TestException() { - super("test-exception"); - } - } - - @Test - public void testComplete() throws Exception { - CompletableFuture future = FutureUtils.createFuture(); - FutureUtils.complete(future, 1024L); - assertEquals(1024L, FutureUtils.result(future).longValue()); - } - - @Test(expected = TestException.class) - public void testCompleteExceptionally() throws Exception { - CompletableFuture future = FutureUtils.createFuture(); - FutureUtils.completeExceptionally(future, new TestException()); - FutureUtils.result(future); - } - - @Test - public void testWhenCompleteAsync() throws Exception { - OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-when-complete-async") - .numThreads(1) - .build(); - AtomicLong resultHolder = new AtomicLong(0L); - CountDownLatch latch = new CountDownLatch(1); - CompletableFuture future = FutureUtils.createFuture(); - FutureUtils.whenCompleteAsync( - future, - (result, cause) -> { - resultHolder.set(result); - latch.countDown(); - }, - scheduler, - new Object()); - FutureUtils.complete(future, 1234L); - latch.await(); - assertEquals(1234L, resultHolder.get()); - } - - @Test - public void testProxyToSuccess() throws Exception { - CompletableFuture src = FutureUtils.createFuture(); - CompletableFuture target = FutureUtils.createFuture(); - FutureUtils.proxyTo(src, target); - FutureUtils.complete(src, 10L); - assertEquals(10L, FutureUtils.result(target).longValue()); - } - - @Test(expected = TestException.class) - public void testProxyToFailure() throws Exception { - CompletableFuture src = FutureUtils.createFuture(); - CompletableFuture target = FutureUtils.createFuture(); - FutureUtils.proxyTo(src, target); - FutureUtils.completeExceptionally(src, new TestException()); - FutureUtils.result(target); - } - - @Test - public void testVoid() throws Exception { - CompletableFuture voidFuture = FutureUtils.Void(); - assertTrue(voidFuture.isDone()); - assertFalse(voidFuture.isCompletedExceptionally()); - assertFalse(voidFuture.isCancelled()); - } - - @Test - public void testCollectEmptyList() throws Exception { - List> futures = Lists.newArrayList(); - List result = FutureUtils.result(FutureUtils.collect(futures)); - assertTrue(result.isEmpty()); - } - - @Test - public void testCollectTenItems() throws Exception { - List> futures = Lists.newArrayList(); - List expectedResults = Lists.newArrayList(); - for (int i = 0; i < 10; i++) { - futures.add(FutureUtils.value(i)); - expectedResults.add(i); - } - List results = FutureUtils.result(FutureUtils.collect(futures)); - assertEquals(expectedResults, results); - } - - @Test(expected = TestException.class) - public void testCollectFailures() throws Exception { - List> futures = Lists.newArrayList(); - List expectedResults = Lists.newArrayList(); - for (int i = 0; i < 10; i++) { - if (i == 9) { - futures.add(FutureUtils.value(i)); - } else { - futures.add(FutureUtils.exception(new TestException())); - } - expectedResults.add(i); - } - FutureUtils.result(FutureUtils.collect(futures)); - } - - @Test - public void testWithinAlreadyDone() throws Exception { - OrderedScheduler scheduler = mock(OrderedScheduler.class); - CompletableFuture doneFuture = FutureUtils.value(1234L); - CompletableFuture withinFuture = FutureUtils.within( - doneFuture, - 10, - TimeUnit.MILLISECONDS, - new TestException(), - scheduler, - 1234L); - TimeUnit.MILLISECONDS.sleep(20); - assertTrue(withinFuture.isDone()); - assertFalse(withinFuture.isCancelled()); - assertFalse(withinFuture.isCompletedExceptionally()); - verify(scheduler, times(0)) - .scheduleOrdered(eq(1234L), isA(Runnable.class), eq(10), eq(TimeUnit.MILLISECONDS)); - } - - @Test - public void testWithinZeroTimeout() throws Exception { - OrderedScheduler scheduler = mock(OrderedScheduler.class); - CompletableFuture newFuture = FutureUtils.createFuture(); - CompletableFuture withinFuture = FutureUtils.within( - newFuture, - 0, - TimeUnit.MILLISECONDS, - new TestException(), - scheduler, - 1234L); - TimeUnit.MILLISECONDS.sleep(20); - assertFalse(withinFuture.isDone()); - assertFalse(withinFuture.isCancelled()); - assertFalse(withinFuture.isCompletedExceptionally()); - verify(scheduler, times(0)) - .scheduleOrdered(eq(1234L), isA(Runnable.class), eq(10), eq(TimeUnit.MILLISECONDS)); - } - - @Test - public void testWithinCompleteBeforeTimeout() throws Exception { - OrderedScheduler scheduler = mock(OrderedScheduler.class); - ScheduledFuture scheduledFuture = mock(ScheduledFuture.class); - when(scheduler.scheduleOrdered(any(Object.class), any(Runnable.class), anyLong(), any(TimeUnit.class))) - .thenAnswer(invocationOnMock -> scheduledFuture); - CompletableFuture newFuture = FutureUtils.createFuture(); - CompletableFuture withinFuture = FutureUtils.within( - newFuture, - Long.MAX_VALUE, - TimeUnit.MILLISECONDS, - new TestException(), - scheduler, - 1234L); - assertFalse(withinFuture.isDone()); - assertFalse(withinFuture.isCancelled()); - assertFalse(withinFuture.isCompletedExceptionally()); - - newFuture.complete(5678L); - - assertTrue(withinFuture.isDone()); - assertFalse(withinFuture.isCancelled()); - assertFalse(withinFuture.isCompletedExceptionally()); - assertEquals((Long) 5678L, FutureUtils.result(withinFuture)); - - verify(scheduledFuture, times(1)) - .cancel(eq(true)); - } - - @Test - public void testIgnoreSuccess() { - CompletableFuture underlyFuture = FutureUtils.createFuture(); - CompletableFuture ignoredFuture = FutureUtils.ignore(underlyFuture); - underlyFuture.complete(1234L); - assertTrue(ignoredFuture.isDone()); - assertFalse(ignoredFuture.isCompletedExceptionally()); - assertFalse(ignoredFuture.isCancelled()); - } - - @Test - public void testIgnoreFailure() { - CompletableFuture underlyFuture = FutureUtils.createFuture(); - CompletableFuture ignoredFuture = FutureUtils.ignore(underlyFuture); - underlyFuture.completeExceptionally(new TestException()); - assertTrue(ignoredFuture.isDone()); - assertFalse(ignoredFuture.isCompletedExceptionally()); - assertFalse(ignoredFuture.isCancelled()); - } - - @Test - public void testEnsureSuccess() throws Exception { - CountDownLatch ensureLatch = new CountDownLatch(1); - CompletableFuture underlyFuture = FutureUtils.createFuture(); - CompletableFuture ensuredFuture = FutureUtils.ensure(underlyFuture, () -> { - ensureLatch.countDown(); - }); - underlyFuture.complete(1234L); - FutureUtils.result(ensuredFuture); - assertTrue(ensuredFuture.isDone()); - assertFalse(ensuredFuture.isCompletedExceptionally()); - assertFalse(ensuredFuture.isCancelled()); - ensureLatch.await(); - } - - @Test - public void testEnsureFailure() throws Exception { - CountDownLatch ensureLatch = new CountDownLatch(1); - CompletableFuture underlyFuture = FutureUtils.createFuture(); - CompletableFuture ensuredFuture = FutureUtils.ensure(underlyFuture, () -> { - ensureLatch.countDown(); - }); - underlyFuture.completeExceptionally(new TestException()); - FutureUtils.result(FutureUtils.ignore(ensuredFuture)); - assertTrue(ensuredFuture.isDone()); - assertTrue(ensuredFuture.isCompletedExceptionally()); - assertFalse(ensuredFuture.isCancelled()); - ensureLatch.await(); - } - - @Test - @SuppressWarnings("unchecked") - public void testRescueSuccess() throws Exception { - CompletableFuture underlyFuture = FutureUtils.createFuture(); - Function> rescueFuc = mock(Function.class); - CompletableFuture rescuedFuture = FutureUtils.rescue(underlyFuture, rescueFuc); - underlyFuture.complete(1234L); - FutureUtils.result(rescuedFuture); - assertTrue(rescuedFuture.isDone()); - assertFalse(rescuedFuture.isCompletedExceptionally()); - assertFalse(rescuedFuture.isCancelled()); - verify(rescueFuc, times(0)).apply(any(Throwable.class)); - } - - @Test - public void testRescueFailure() throws Exception { - CompletableFuture futureCompletedAtRescue = FutureUtils.value(3456L); - CompletableFuture underlyFuture = FutureUtils.createFuture(); - CompletableFuture rescuedFuture = FutureUtils.rescue(underlyFuture, (cause) -> futureCompletedAtRescue); - underlyFuture.completeExceptionally(new TestException()); - FutureUtils.result(rescuedFuture); - assertTrue(rescuedFuture.isDone()); - assertFalse(rescuedFuture.isCompletedExceptionally()); - assertFalse(rescuedFuture.isCancelled()); - assertEquals((Long) 3456L, FutureUtils.result(rescuedFuture)); - } - - @Test - public void testStatsSuccess() throws Exception { - OpStatsLogger statsLogger = mock(OpStatsLogger.class); - CompletableFuture underlyFuture = FutureUtils.createFuture(); - CompletableFuture statsFuture = FutureUtils.stats( - underlyFuture, - statsLogger, - Stopwatch.createStarted()); - underlyFuture.complete(1234L); - FutureUtils.result(statsFuture); - verify(statsLogger, times(1)) - .registerSuccessfulEvent(anyLong(), eq(TimeUnit.MICROSECONDS)); - } - - @Test - public void testStatsFailure() throws Exception { - OpStatsLogger statsLogger = mock(OpStatsLogger.class); - CompletableFuture underlyFuture = FutureUtils.createFuture(); - CompletableFuture statsFuture = FutureUtils.stats( - underlyFuture, - statsLogger, - Stopwatch.createStarted()); - underlyFuture.completeExceptionally(new TestException()); - FutureUtils.result(FutureUtils.ignore(statsFuture)); - verify(statsLogger, times(1)) - .registerFailedEvent(anyLong(), eq(TimeUnit.MICROSECONDS)); - } - - @Test - public void testProcessListSuccess() throws Exception { - List longList = Lists.newArrayList(LongStream.range(0L, 10L).iterator()); - List expectedList = Lists.transform( - longList, - aLong -> 2 * aLong); - Function> sumFunc = value -> FutureUtils.value(2 * value); - CompletableFuture> totalFuture = FutureUtils.processList( - longList, - sumFunc, - null); - assertEquals(expectedList, FutureUtils.result(totalFuture)); - } - - @Test - public void testProcessEmptyList() throws Exception { - List longList = Lists.newArrayList(); - List expectedList = Lists.transform( - longList, - aLong -> 2 * aLong); - Function> sumFunc = value -> FutureUtils.value(2 * value); - CompletableFuture> totalFuture = FutureUtils.processList( - longList, - sumFunc, - null); - assertEquals(expectedList, FutureUtils.result(totalFuture)); - } - - @Test - public void testProcessListFailures() throws Exception { - List longList = Lists.newArrayList(LongStream.range(0L, 10L).iterator()); - AtomicLong total = new AtomicLong(0L); - Function> sumFunc = value -> { - if (value < 5) { - total.addAndGet(value); - return FutureUtils.value(2 * value); - } else { - return FutureUtils.exception(new TestException()); - } - }; - CompletableFuture> totalFuture = FutureUtils.processList( - longList, - sumFunc, - null); - try { - FutureUtils.result(totalFuture); - fail("Should fail with TestException"); - } catch (TestException te) { - // as expected - } - assertEquals(10L, total.get()); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigDefTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigDefTest.java deleted file mode 100644 index 7ba3e71ccae..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigDefTest.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.conf; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import com.google.common.io.ByteStreams; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Iterator; -import java.util.Set; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.conf.validators.ClassValidator; -import org.apache.bookkeeper.common.conf.validators.RangeValidator; -import org.junit.Test; - -/** - * Unit test {@link ConfigDef}. - */ -@Slf4j -public class ConfigDefTest { - - private static class TestConfig { - - private static final ConfigKeyGroup group1 = ConfigKeyGroup.builder("group1") - .description("Group 1 Settings") - .order(1) - .build(); - - private static final ConfigKey key11 = ConfigKey.builder("key11") - .type(Type.LONG) - .group(group1) - .validator(RangeValidator.atLeast(1000)) - .build(); - - private static final ConfigKeyGroup group2 = ConfigKeyGroup.builder("group2") - .description("Group 2 Settings") - .order(2) - .build(); - - private static final ConfigKey key21 = ConfigKey.builder("key21") - .type(Type.LONG) - .group(group2) - .validator(RangeValidator.atMost(1000)) - .orderInGroup(2) - .build(); - - private static final ConfigKey key22 = ConfigKey.builder("key22") - .type(Type.STRING) - .group(group2) - .validator(ClassValidator.of(Runnable.class)) - .orderInGroup(1) - .build(); - - } - - private static class TestConfig2 { - - private static final ConfigKeyGroup emptyGroup = ConfigKeyGroup.builder("empty_group") - .description("Empty Group Settings") - .order(1) - .build(); - - private static final ConfigKeyGroup group1 = ConfigKeyGroup.builder("group1") - .description("This is a very long description : Lorem ipsum dolor sit amet," - + " consectetur adipiscing elit. Maecenas bibendum ac felis id commodo." - + " Etiam mauris purus, fringilla id tempus in, mollis vel orci. Duis" - + " ultricies at erat eget iaculis.") - .order(2) - .build(); - - private static final ConfigKey intKey = ConfigKey.builder("int_key") - .type(Type.INT) - .description("it is an int key") - .group(group1) - .validator(RangeValidator.atLeast(1000)) - .build(); - - private static final ConfigKey longKey = ConfigKey.builder("long_key") - .type(Type.LONG) - .description("it is a long key") - .group(group1) - .validator(RangeValidator.atMost(1000)) - .build(); - - private static final ConfigKey shortKey = ConfigKey.builder("short_key") - .type(Type.SHORT) - .description("it is a short key") - .group(group1) - .validator(RangeValidator.between(500, 1000)) - .build(); - - private static final ConfigKey doubleKey = ConfigKey.builder("double_key") - .type(Type.DOUBLE) - .description("it is a double key") - .group(group1) - .validator(RangeValidator.between(1234.0f, 5678.0f)) - .build(); - - private static final ConfigKey boolKey = ConfigKey.builder("bool_key") - .type(Type.BOOLEAN) - .description("it is a bool key") - .group(group1) - .build(); - - private static final ConfigKey classKey = ConfigKey.builder("class_key") - .type(Type.CLASS) - .description("it is a class key") - .validator(ClassValidator.of(Runnable.class)) - .group(group1) - .build(); - - private static final ConfigKey listKey = ConfigKey.builder("list_key") - .type(Type.LIST) - .description("it is a list key") - .group(group1) - .build(); - - private static final ConfigKey stringKey = ConfigKey.builder("string_key") - .type(Type.STRING) - .description("it is a string key") - .group(group1) - .build(); - - private static final ConfigKeyGroup group2 = ConfigKeyGroup.builder("group2") - .description("This group has short description") - .order(3) - .build(); - - private static final ConfigKey keyWithSince = ConfigKey.builder("key_with_since") - .type(Type.STRING) - .description("it is a string key with since") - .since("4.7.0") - .group(group2) - .orderInGroup(10) - .build(); - - private static final ConfigKey keyWithDocumentation = ConfigKey.builder("key_with_short_documentation") - .type(Type.STRING) - .description("it is a string key with documentation") - .documentation("it has a short documentation") - .group(group2) - .orderInGroup(9) - .build(); - - private static final ConfigKey keyWithLongDocumentation = - ConfigKey.builder("key_long_short_documentation") - .type(Type.STRING) - .description("it is a string key with documentation") - .documentation("it has a long documentation : Lorem ipsum dolor sit amet," - + " consectetur adipiscing elit. Maecenas bibendum ac felis id commodo." - + " Etiam mauris purus, fringilla id tempus in, mollis vel orci. Duis" - + " ultricies at erat eget iaculis.") - .group(group2) - .orderInGroup(8) - .build(); - - private static final ConfigKey keyWithDefaultValue = ConfigKey.builder("key_with_default_value") - .type(Type.STRING) - .description("it is a string key with default value") - .defaultValue("this-is-a-test-value") - .group(group2) - .orderInGroup(7) - .build(); - - private static final ConfigKey keyWithOptionalValues = ConfigKey.builder("key_with_optional_values") - .type(Type.STRING) - .description("it is a string key with optional values") - .defaultValue("this-is-a-default-value") - .optionValues(Lists.newArrayList( - "item1", "item2", "item3", "item3" - )) - .group(group2) - .orderInGroup(6) - .build(); - - private static final ConfigKey deprecatedKey = ConfigKey.builder("deprecated_key") - .type(Type.STRING) - .deprecated(true) - .description("it is a deprecated key") - .group(group2) - .orderInGroup(5) - .build(); - - private static final ConfigKey deprecatedKeyWithSince = ConfigKey.builder("deprecated_key_with_since") - .type(Type.STRING) - .deprecated(true) - .deprecatedSince("4.3.0") - .description("it is a deprecated key with since") - .group(group2) - .orderInGroup(4) - .build(); - - private static final ConfigKey deprecatedKeyWithReplacedKey = - ConfigKey.builder("deprecated_key_with_replaced_key") - .type(Type.STRING) - .deprecated(true) - .deprecatedByConfigKey("key_with_optional_values") - .description("it is a deprecated key with replaced key") - .group(group2) - .orderInGroup(3) - .build(); - - private static final ConfigKey deprecatedKeyWithSinceAndReplacedKey = - ConfigKey.builder("deprecated_key_with_since_and_replaced_key") - .type(Type.STRING) - .deprecated(true) - .deprecatedSince("4.3.0") - .deprecatedByConfigKey("key_with_optional_values") - .description("it is a deprecated key with since and replaced key") - .group(group2) - .orderInGroup(2) - .build(); - - private static final ConfigKey requiredKey = ConfigKey.builder("required_key") - .type(Type.STRING) - .required(true) - .description("it is a required key") - .group(group2) - .orderInGroup(1) - .build(); - - } - - @Test - public void testBuildConfigDef() { - ConfigDef configDef = ConfigDef.of(TestConfig.class); - assertEquals(2, configDef.getGroups().size()); - - Iterator grpIter = configDef.getGroups().iterator(); - - // iterate over group 1 - assertTrue(grpIter.hasNext()); - ConfigKeyGroup group1 = grpIter.next(); - assertSame(TestConfig.group1, group1); - Set keys = configDef.getSettings().get(group1.name()); - assertNotNull(keys); - assertEquals(1, keys.size()); - assertEquals(TestConfig.key11, keys.iterator().next()); - - // iterate over group 2 - assertTrue(grpIter.hasNext()); - ConfigKeyGroup group2 = grpIter.next(); - assertSame(TestConfig.group2, group2); - keys = configDef.getSettings().get(group2.name()); - assertNotNull(keys); - assertEquals(2, keys.size()); - Iterator keyIter = keys.iterator(); - assertEquals(TestConfig.key22, keyIter.next()); - assertEquals(TestConfig.key21, keyIter.next()); - assertFalse(keyIter.hasNext()); - - // no more group - assertFalse(grpIter.hasNext()); - } - - @Test - public void testSaveConfigDef() throws IOException { - byte[] confData; - try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("test_conf_2.conf")) { - confData = new byte[is.available()]; - ByteStreams.readFully(is, confData); - } - - ConfigDef configDef = ConfigDef.of(TestConfig2.class); - String readConf; - try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - configDef.save(baos); - readConf = baos.toString(); - log.info("\n{}", readConf); - } - - assertEquals(new String(confData, UTF_8), readConf); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyGroupTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyGroupTest.java deleted file mode 100644 index a8abefa7b3d..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyGroupTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.conf; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test {@link ConfigKeyGroup}. - */ -public class ConfigKeyGroupTest { - - @Test - public void testEquals() { - ConfigKeyGroup grp1 = ConfigKeyGroup.builder("group1") - .description("test group 1") - .build(); - ConfigKeyGroup anotherGrp1 = ConfigKeyGroup.builder("group1") - .description("test another group 1") - .build(); - - assertEquals(grp1, anotherGrp1); - } - - @Test - public void testOrdering() { - ConfigKeyGroup grp10 = ConfigKeyGroup.builder("group1") - .order(0) - .build(); - ConfigKeyGroup grp20 = ConfigKeyGroup.builder("group2") - .order(0) - .build(); - ConfigKeyGroup grp21 = ConfigKeyGroup.builder("group2") - .order(1) - .build(); - - assertTrue(ConfigKeyGroup.ORDERING.compare(grp10, grp20) < 0); - assertTrue(ConfigKeyGroup.ORDERING.compare(grp20, grp21) < 0); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyTest.java deleted file mode 100644 index 858a615db54..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyTest.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.conf; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Function; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test {@link ConfigKey}. - */ -public class ConfigKeyTest { - - /** - * Test Function A. - */ - private static class TestFunctionA implements Function { - - @Override - public String apply(String s) { - return s + "!"; - } - } - - /** - * Test Function B. - */ - private static class TestFunctionB implements Function { - - @Override - public String apply(String s) { - return s + "!"; - } - } - - /** - * Test Function C. - */ - private static class TestFunctionC implements Function { - - @Override - public String apply(String s) { - return s + "!"; - } - } - - @Rule - public final TestName runtime = new TestName(); - - @Test - public void testValidateRequiredField() { - String keyName = runtime.getMethodName(); - Configuration conf = new ConcurrentConfiguration(); - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .build(); - - try { - key.validate(conf); - fail("Required key should exist in the configuration"); - } catch (ConfigException ce) { - // expected - } - } - - @Test - public void testValidateFieldSuccess() throws ConfigException { - String keyName = runtime.getMethodName(); - Validator validator = mock(Validator.class); - when(validator.validate(anyString(), any())).thenReturn(true); - Configuration conf = new ConcurrentConfiguration(); - conf.setProperty(keyName, "test-value"); - ConfigKey key = ConfigKey.builder(keyName) - .validator(validator) - .build(); - - key.validate(conf); - verify(validator, times(1)).validate(eq(keyName), eq("test-value")); - } - - @Test - public void testValidateFieldFailure() { - String keyName = runtime.getMethodName(); - Validator validator = mock(Validator.class); - when(validator.validate(anyString(), any())).thenReturn(false); - Configuration conf = new ConcurrentConfiguration(); - conf.setProperty(keyName, "test-value"); - ConfigKey key = ConfigKey.builder(keyName) - .validator(validator) - .build(); - - try { - key.validate(conf); - fail("Should fail validation if validator#validate returns false"); - } catch (ConfigException ce) { - // expected - } - verify(validator, times(1)).validate(eq(keyName), eq("test-value")); - } - - @Test - public void testGetLong() { - String keyName = runtime.getMethodName(); - long defaultValue = System.currentTimeMillis(); - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.LONG) - .defaultValue(defaultValue) - .build(); - - Configuration conf = new ConcurrentConfiguration(); - - // get default value - assertEquals(defaultValue, key.getLong(conf)); - assertEquals(defaultValue, key.get(conf)); - - // set value - long newValue = System.currentTimeMillis() * 2; - key.set(conf, newValue); - assertEquals(newValue, key.getLong(conf)); - assertEquals(newValue, key.get(conf)); - } - - @Test - public void testGetInt() { - String keyName = runtime.getMethodName(); - int defaultValue = ThreadLocalRandom.current().nextInt(10000); - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.INT) - .defaultValue(defaultValue) - .build(); - - Configuration conf = new ConcurrentConfiguration(); - - // get default value - assertEquals(defaultValue, key.getInt(conf)); - assertEquals(defaultValue, key.get(conf)); - - // set value - int newValue = defaultValue * 2; - key.set(conf, newValue); - assertEquals(newValue, key.getInt(conf)); - assertEquals(newValue, key.get(conf)); - } - - @Test - public void testGetShort() { - String keyName = runtime.getMethodName(); - short defaultValue = (short) ThreadLocalRandom.current().nextInt(10000); - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.SHORT) - .defaultValue(defaultValue) - .build(); - - Configuration conf = new ConcurrentConfiguration(); - - // get default value - assertEquals(defaultValue, key.getShort(conf)); - assertEquals(defaultValue, key.get(conf)); - - // set value - short newValue = (short) (defaultValue * 2); - key.set(conf, newValue); - assertEquals(newValue, key.getShort(conf)); - assertEquals(newValue, key.get(conf)); - } - - @Test - public void testGetDouble() { - String keyName = runtime.getMethodName(); - double defaultValue = ThreadLocalRandom.current().nextDouble(10000.0f); - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.DOUBLE) - .defaultValue(defaultValue) - .build(); - - Configuration conf = new ConcurrentConfiguration(); - - // get default value - assertEquals(defaultValue, key.getDouble(conf), 0.0001); - assertEquals(defaultValue, key.get(conf)); - - // set value - double newValue = (defaultValue * 2); - key.set(conf, newValue); - assertEquals(newValue, key.getDouble(conf), 0.0001); - assertEquals(newValue, key.get(conf)); - } - - @Test - public void testGetBoolean() { - String keyName = runtime.getMethodName(); - boolean defaultValue = ThreadLocalRandom.current().nextBoolean(); - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.BOOLEAN) - .defaultValue(defaultValue) - .build(); - - Configuration conf = new ConcurrentConfiguration(); - - // get default value - assertEquals(defaultValue, key.getBoolean(conf)); - assertEquals(defaultValue, key.get(conf)); - - // set value - boolean newValue = !defaultValue; - key.set(conf, newValue); - assertEquals(newValue, key.getBoolean(conf)); - assertEquals(newValue, key.get(conf)); - } - - @Test - public void testGetList() { - String keyName = runtime.getMethodName(); - List defaultList = Lists.newArrayList( - "item1", "item2", "item3" - ); - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.LIST) - .defaultValue(defaultList) - .build(); - - Configuration conf = new CompositeConfiguration(); - - // get default value - assertEquals(defaultList, key.getList(conf)); - assertEquals(defaultList, key.get(conf)); - - // set value - List newList = Lists.newArrayList( - "item4", "item5", "item6" - ); - key.set(conf, newList); - assertEquals(newList, key.getList(conf)); - assertEquals(newList, key.get(conf)); - - // set string value - newList = Lists.newArrayList( - "item7", "item8", "item9" - ); - conf.setProperty(key.name(), "item7,item8,item9"); - assertEquals(newList, key.getList(conf)); - assertEquals(newList, key.get(conf)); - } - - @Test - public void testGetClass() { - String keyName = runtime.getMethodName(); - Class defaultClass = TestFunctionA.class; - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.CLASS) - .defaultValue(defaultClass) - .build(); - - Configuration conf = new CompositeConfiguration(); - - // get default value - assertEquals(defaultClass, key.getClass(conf)); - assertEquals(defaultClass, key.get(conf)); - - // set value - Class newClass = TestFunctionB.class; - key.set(conf, newClass); - assertEquals(newClass, key.getClass(conf)); - assertEquals(newClass, key.get(conf)); - - // set string value - String newClassName = TestFunctionC.class.getName(); - conf.setProperty(key.name(), newClassName); - assertEquals(TestFunctionC.class, key.getClass(conf)); - assertEquals(TestFunctionC.class, key.get(conf)); - } - - @Test - public void testGetString() { - String keyName = runtime.getMethodName(); - String defaultValue = "default-string-value"; - ConfigKey key = ConfigKey.builder(keyName) - .required(true) - .type(Type.STRING) - .defaultValue(defaultValue) - .build(); - - Configuration conf = new CompositeConfiguration(); - - // get default value - assertEquals(defaultValue, key.getString(conf)); - assertEquals(defaultValue, key.get(conf)); - - // set value - String newValue = "new-string-value"; - key.set(conf, newValue); - assertEquals(newValue, key.getString(conf)); - assertEquals(newValue, key.get(conf)); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/ClassValidatorTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/ClassValidatorTest.java deleted file mode 100644 index bfb7971b45b..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/ClassValidatorTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.conf.validators; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.function.Function; -import org.junit.Test; - -/** - * Unit test for {@link ClassValidator}. - */ -public class ClassValidatorTest { - - private static class TestFunction implements Function { - - @Override - public String apply(String s) { - return s + "!"; - } - } - - @Test - public void testValidateStrings() { - ClassValidator validator = ClassValidator.of(Function.class); - assertTrue(validator.validate("test-valid-classname", TestFunction.class.getName())); - assertFalse(validator.validate("test-invalid-classname", "unknown")); - } - - @Test - public void testValidateClass() { - ClassValidator validator = ClassValidator.of(Function.class); - assertTrue(validator.validate("test-valid-class", TestFunction.class)); - assertFalse(validator.validate("test-invalid-class", Integer.class)); - } - - @Test - public void testValidateWrongType() { - ClassValidator validator = ClassValidator.of(Function.class); - assertFalse(validator.validate("test-invalid-type", 12345)); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/RangeValidatorTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/RangeValidatorTest.java deleted file mode 100644 index b8725957c2a..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/RangeValidatorTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.conf.validators; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test {@link RangeValidator} validator. - */ -public class RangeValidatorTest { - - @Test - public void testAtLeastRangeValidator() { - RangeValidator range = RangeValidator.atLeast(1234L); - assertTrue(range.validate("test-0", 1235L)); - assertTrue(range.validate("test-1", 1234L)); - assertFalse(range.validate("test-2", 1233L)); - } - - @Test - public void testAtMostRangeValidator() { - RangeValidator range = RangeValidator.atMost(1234L); - assertFalse(range.validate("test-0", 1235L)); - assertTrue(range.validate("test-1", 1234L)); - assertTrue(range.validate("test-2", 1233L)); - } - - @Test - public void testBetweenRangeValidator() { - RangeValidator range = RangeValidator.between(1230L, 1240L); - assertTrue(range.validate("test-0", 1230L)); - assertTrue(range.validate("test-1", 1235L)); - assertTrue(range.validate("test-2", 1240L)); - assertFalse(range.validate("test-3", 1229L)); - assertFalse(range.validate("test-4", 1241L)); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java deleted file mode 100644 index 2ec83df32c0..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.net; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.net.URI; -import org.junit.Test; - -/** - * Unit test {@link ServiceURI}. - */ -public class ServiceURITest { - - private static void assertServiceUri( - String serviceUri, - String expectedServiceName, - String[] expectedServiceInfo, - String expectedServiceUser, - String[] expectedServiceHosts, - String expectedServicePath) { - - ServiceURI serviceURI = ServiceURI.create(serviceUri); - - assertEquals(expectedServiceName, serviceURI.getServiceName()); - assertArrayEquals(expectedServiceInfo, serviceURI.getServiceInfos()); - assertEquals(expectedServiceUser, serviceURI.getServiceUser()); - assertArrayEquals(expectedServiceHosts, serviceURI.getServiceHosts()); - assertEquals(expectedServicePath, serviceURI.getServicePath()); - } - - @Test - public void testInvalidServiceUris() { - String[] uris = new String[] { - "://localhost:2181/path/to/namespace", // missing scheme - "bk:///path/to/namespace", // missing authority - "bk://localhost:2181:3181/path/to/namespace", // invalid hostname pair - "bk://localhost:xyz/path/to/namespace", // invalid port - "bk://localhost:-2181/path/to/namespace", // negative port - }; - - for (String uri : uris) { - testInvalidServiceUri(uri); - } - } - - @Test(expected = NullPointerException.class) - public void testNullServiceUriString() { - ServiceURI.create((String) null); - } - - @Test(expected = NullPointerException.class) - public void testNullServiceUriInstance() { - ServiceURI.create((URI) null); - } - - @Test(expected = IllegalArgumentException.class) - public void testEmptyServiceUriString() { - ServiceURI.create(""); - } - - private void testInvalidServiceUri(String serviceUri) { - try { - ServiceURI.create(serviceUri); - fail("Should fail to parse service uri : " + serviceUri); - } catch (IllegalArgumentException iae) { - // expected - } - } - - @Test - public void testMissingServiceName() { - String serviceUri = "//localhost:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - null, new String[0], null, new String[] { "localhost:2181" }, "/path/to/namespace"); - } - - @Test - public void testEmptyPath() { - String serviceUri = "bk://localhost:2181"; - assertServiceUri( - serviceUri, - "bk", new String[0], null, new String[] { "localhost:2181" }, ""); - } - - @Test - public void testRootPath() { - String serviceUri = "bk://localhost:2181/"; - assertServiceUri( - serviceUri, - "bk", new String[0], null, new String[] { "localhost:2181" }, "/"); - } - - @Test - public void testUserInfo() { - String serviceUri = "bk://bookkeeper@localhost:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[0], - "bookkeeper", - new String[] { "localhost:2181" }, - "/path/to/namespace"); - } - - @Test - public void testMultipleHostsSemiColon() { - String serviceUri = "bk://host1:2181;host2:2181;host3:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[0], - null, - new String[] { "host1:2181", "host2:2181", "host3:2181" }, - "/path/to/namespace"); - } - - @Test - public void testMultipleHostsComma() { - String serviceUri = "bk://host1:2181,host2:2181,host3:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[0], - null, - new String[] { "host1:2181", "host2:2181", "host3:2181" }, - "/path/to/namespace"); - } - - @Test - public void testMultipleHostsWithoutPorts() { - String serviceUri = "bk://host1,host2,host3/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[0], - null, - new String[] { "host1:4181", "host2:4181", "host3:4181" }, - "/path/to/namespace"); - } - - @Test - public void testMultipleHostsMixedPorts() { - String serviceUri = "bk://host1:3181,host2,host3:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[0], - null, - new String[] { "host1:3181", "host2:4181", "host3:2181" }, - "/path/to/namespace"); - } - - @Test - public void testMultipleHostsMixed() { - String serviceUri = "bk://host1:2181,host2,host3:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[0], - null, - new String[] { "host1:2181", "host2:4181", "host3:2181" }, - "/path/to/namespace"); - } - - @Test - public void testUserInfoWithMultipleHosts() { - String serviceUri = "bk://bookkeeper@host1:2181;host2:2181;host3:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[0], - "bookkeeper", - new String[] { "host1:2181", "host2:2181", "host3:2181" }, - "/path/to/namespace"); - } - - @Test - public void testServiceInfoPlus() { - String serviceUri = "bk+ssl://host:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk", - new String[] { "ssl" }, - null, - new String[] { "host:2181" }, - "/path/to/namespace"); - } - - @Test - public void testServiceInfoMinus() { - String serviceUri = "bk-ssl://host:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "bk-ssl", - new String[0], - null, - new String[] { "host:2181" }, - "/path/to/namespace"); - } - - @Test - public void testServiceInfoDlogMinus() { - String serviceUri = "distributedlog-bk://host:2181/path/to/namespace"; - assertServiceUri( - serviceUri, - "distributedlog", - new String[] { "bk" }, - null, - new String[] { "host:2181" }, - "/path/to/namespace"); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/MoreAsserts.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/MoreAsserts.java deleted file mode 100644 index b62c8ae7bb5..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/MoreAsserts.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.testing; - -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Sets; -import com.google.common.collect.Sets.SetView; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; -import java.util.function.Supplier; - -/** - * Assertion utils. - */ -public final class MoreAsserts { - - private MoreAsserts() {} - - public static void assertSetEquals(Set expected, Set actual) { - SetView diff = Sets.difference(expected, actual); - assertTrue( - "Expected set contains items not exist at actual set : " + diff.immutableCopy(), - diff.isEmpty()); - diff = Sets.difference(actual, expected); - assertTrue( - "Actual set contains items not exist at expected set : " + diff.immutableCopy(), - diff.isEmpty()); - } - - public static void assertUtil(Predicate predicate, Supplier supplier) throws InterruptedException { - while (!predicate.test(supplier.get())) { - TimeUnit.MILLISECONDS.sleep(100); - } - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/annotations/FlakyTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/annotations/FlakyTest.java deleted file mode 100644 index 27c26b123d6..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/annotations/FlakyTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.testing.annotations; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Intended for marking a test case as flaky. - */ -@Documented -@Retention(RetentionPolicy.SOURCE) -public @interface FlakyTest { - - /** - * Context information such as links to discussion thread, tracking issues etc. - * - * @return context information about this flaky test. - */ - String value(); -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClock.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClock.java deleted file mode 100644 index 7a640ca8364..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClock.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.testing.executors; - -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; - -/** - * A mock implementation of {@link Clock}. - */ -public class MockClock extends Clock { - - private final ZoneId zoneId; - private Instant now = Instant.ofEpochMilli(0); - - public MockClock() { - this(ZoneId.systemDefault()); - } - - private MockClock(ZoneId zoneId) { - this.zoneId = zoneId; - } - - @Override - public ZoneId getZone() { - return zoneId; - } - - @Override - public MockClock withZone(ZoneId zone) { - return new MockClock(zone); - } - - @Override - public Instant instant() { - return now; - } - - /** - * Advance the clock by the given amount of time. - * - * @param duration duration to advance. - */ - public void advance(Duration duration) { - now = now.plus(duration); - } -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClockTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClockTest.java deleted file mode 100644 index 7ca32799305..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClockTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.testing.executors; - -import static org.junit.Assert.assertEquals; - -import java.time.Duration; -import org.junit.Before; -import org.junit.Test; - -/** - * Test {@link MockClock}. - */ -public class MockClockTest { - - private MockClock clock; - - @Before - public void setup() { - this.clock = new MockClock(); - } - - @Test - public void testAdvance() { - assertEquals(0L, clock.millis()); - clock.advance(Duration.ofMillis(10)); - assertEquals(10L, clock.millis()); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorController.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorController.java deleted file mode 100644 index 4942e348bac..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorController.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.testing.executors; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doAnswer; - -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.SettableFuture; -import java.time.Duration; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import lombok.AccessLevel; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.mockito.stubbing.Answer; - -/** - * A mocked scheduled executor that records scheduled tasks and executes them when the clock is - * advanced past their execution time. - */ -@Slf4j -@NoArgsConstructor(access = AccessLevel.PUBLIC) -public class MockExecutorController { - - @Data - @Getter - private class DeferredTask implements ScheduledFuture { - - private final Runnable runnable; - private final long scheduledAtMillis; - @Getter - private final CompletableFuture future; - - public DeferredTask(Runnable runnable, - long delayTimeMs) { - this.runnable = runnable; - this.scheduledAtMillis = delayTimeMs + clock.millis(); - this.future = FutureUtils.createFuture(); - } - - @Override - public long getDelay(TimeUnit unit) { - return unit.convert(scheduledAtMillis - clock.millis(), TimeUnit.MILLISECONDS); - } - - @Override - public int compareTo(Delayed o) { - return Long.compare(getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS)); - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return future.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return future.isCancelled(); - } - - @Override - public boolean isDone() { - return future.isDone(); - } - - @Override - public Void get() throws InterruptedException, ExecutionException { - future.get(); - return null; - } - - @Override - public Void get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - future.get(timeout, unit); - return null; - } - - void run() { - runnable.run(); - FutureUtils.complete(future, null); - } - - } - - @Getter - private final MockClock clock = new MockClock(); - private final List deferredTasks = Lists.newArrayList(); - - public MockExecutorController controlSubmit(ScheduledExecutorService service) { - doAnswer(answerNow()).when(service).submit(any(Runnable.class)); - return this; - } - - public MockExecutorController controlExecute(ScheduledExecutorService service) { - doAnswer(answerNow()).when(service).execute(any(Runnable.class)); - return this; - } - - public MockExecutorController controlSchedule(ScheduledExecutorService service) { - doAnswer(answerDelay(this)).when(service).schedule(any(Runnable.class), anyLong(), any(TimeUnit.class)); - return this; - } - - public MockExecutorController controlScheduleAtFixedRate(ScheduledExecutorService service, - int maxInvocations) { - doAnswer(answerAtFixedRate(this, maxInvocations)) - .when(service) - .scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class)); - return this; - } - - private static Answer> answerAtFixedRate(MockExecutorController controller, int numTimes) { - return invocationOnMock -> { - Runnable task = invocationOnMock.getArgument(0); - long initialDelay = invocationOnMock.getArgument(1); - long delay = invocationOnMock.getArgument(2); - TimeUnit unit = invocationOnMock.getArgument(3); - - DeferredTask deferredTask = null; - for (int i = 0; i < numTimes; i++) { - long delayMs = unit.toMillis(initialDelay) + i * unit.toMillis(delay); - - deferredTask = controller.addDelayedTask( - controller, - delayMs, - task); - } - return deferredTask; - }; - } - - private static Answer> answerDelay(MockExecutorController executor) { - return invocationOnMock -> { - - Runnable task = invocationOnMock.getArgument(0); - long value = invocationOnMock.getArgument(1); - TimeUnit unit = invocationOnMock.getArgument(2); - return executor.addDelayedTask(executor, unit.toMillis(value), task); - }; - } - - private static Answer> answerNow() { - return invocationOnMock -> { - - Runnable task = invocationOnMock.getArgument(0); - task.run(); - SettableFuture future = SettableFuture.create(); - future.set(null); - return future; - }; - } - - private DeferredTask addDelayedTask( - MockExecutorController executor, - long delayTimeMs, - Runnable task) { - checkArgument(delayTimeMs >= 0); - DeferredTask deferredTask = new DeferredTask(task, delayTimeMs); - if (delayTimeMs > 0) { - executor.deferredTasks.add(deferredTask); - } else { - task.run(); - FutureUtils.complete(deferredTask.future, null); - } - return deferredTask; - } - - public void advance(Duration duration) { - clock.advance(duration); - Iterator entries = deferredTasks.iterator(); - List toExecute = Lists.newArrayList(); - while (entries.hasNext()) { - DeferredTask next = entries.next(); - if (next.getDelay(TimeUnit.MILLISECONDS) <= 0) { - entries.remove(); - toExecute.add(next); - } - } - for (DeferredTask task : toExecute) { - task.run(); - } - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorControllerTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorControllerTest.java deleted file mode 100644 index 50ea923d940..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorControllerTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.testing.executors; - -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.time.Duration; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.junit.Before; -import org.junit.Test; - -/** - * Test {@link MockExecutorController}. - */ -public class MockExecutorControllerTest { - - private static final int MAX_SCHEDULES = 5; - - private ScheduledExecutorService executor; - private MockExecutorController mockExecutorControl; - - @Before - public void setup() { - this.executor = mock(ScheduledExecutorService.class); - this.mockExecutorControl = new MockExecutorController() - .controlExecute(executor) - .controlSubmit(executor) - .controlSchedule(executor) - .controlScheduleAtFixedRate(executor, MAX_SCHEDULES); - } - - @Test - public void testSubmit() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.submit(task); - verify(task, times(1)).run(); - } - - @Test - public void testExecute() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.execute(task); - verify(task, times(1)).run(); - } - - @Test - public void testDelay() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.schedule(task, 10, TimeUnit.MILLISECONDS); - mockExecutorControl.advance(Duration.ofMillis(5)); - verify(task, times(0)).run(); - mockExecutorControl.advance(Duration.ofMillis(10)); - verify(task, times(1)).run(); - } - - @Test - public void testScheduleAtFixedRate() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.scheduleAtFixedRate(task, 5, 10, TimeUnit.MILLISECONDS); - - // first delay - mockExecutorControl.advance(Duration.ofMillis(2)); - verify(task, times(0)).run(); - mockExecutorControl.advance(Duration.ofMillis(3)); - verify(task, times(1)).run(); - - // subsequent delays - for (int i = 1; i < MAX_SCHEDULES; i++) { - mockExecutorControl.advance(Duration.ofMillis(2)); - verify(task, times(i)).run(); - mockExecutorControl.advance(Duration.ofMillis(8)); - verify(task, times(i + 1)).run(); - } - - // no more invocations - mockExecutorControl.advance(Duration.ofMillis(500)); - verify(task, times(MAX_SCHEDULES)).run(); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TestTimedOutTestsListener.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TestTimedOutTestsListener.java deleted file mode 100644 index 09f2ca5e798..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TestTimedOutTestsListener.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.testing.util; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.notification.Failure; - -/** - * Test Case for {@link TimedOutTestsListener}. - */ -public class TestTimedOutTestsListener { - - private static class Deadlock { - private CyclicBarrier barrier = new CyclicBarrier(6); - - public Deadlock() { - DeadlockThread[] dThreads = new DeadlockThread[6]; - - Monitor a = new Monitor("a"); - Monitor b = new Monitor("b"); - Monitor c = new Monitor("c"); - dThreads[0] = new DeadlockThread("MThread-1", a, b); - dThreads[1] = new DeadlockThread("MThread-2", b, c); - dThreads[2] = new DeadlockThread("MThread-3", c, a); - - Lock d = new ReentrantLock(); - Lock e = new ReentrantLock(); - Lock f = new ReentrantLock(); - - dThreads[3] = new DeadlockThread("SThread-4", d, e); - dThreads[4] = new DeadlockThread("SThread-5", e, f); - dThreads[5] = new DeadlockThread("SThread-6", f, d); - - // make them daemon threads so that the test will exit - for (int i = 0; i < 6; i++) { - dThreads[i].setDaemon(true); - dThreads[i].start(); - } - } - - class DeadlockThread extends Thread { - private Lock lock1 = null; - - private Lock lock2 = null; - - private Monitor mon1 = null; - - private Monitor mon2 = null; - - private boolean useSync; - - DeadlockThread(String name, Lock lock1, Lock lock2) { - super(name); - this.lock1 = lock1; - this.lock2 = lock2; - this.useSync = true; - } - - DeadlockThread(String name, Monitor mon1, Monitor mon2) { - super(name); - this.mon1 = mon1; - this.mon2 = mon2; - this.useSync = false; - } - - public void run() { - if (useSync) { - syncLock(); - } else { - monitorLock(); - } - } - - private void syncLock() { - lock1.lock(); - try { - try { - barrier.await(); - } catch (Exception e) { - } - goSyncDeadlock(); - } finally { - lock1.unlock(); - } - } - - private void goSyncDeadlock() { - try { - barrier.await(); - } catch (Exception e) { - } - lock2.lock(); - throw new RuntimeException("should not reach here."); - } - - private void monitorLock() { - synchronized (mon1) { - try { - barrier.await(); - } catch (Exception e) { - } - goMonitorDeadlock(); - } - } - - private void goMonitorDeadlock() { - try { - barrier.await(); - } catch (Exception e) { - } - synchronized (mon2) { - throw new RuntimeException(getName() + " should not reach here."); - } - } - } - - class Monitor { - String name; - - Monitor(String name) { - this.name = name; - } - } - - } - - @Test(timeout = 500) - public void testThreadDumpAndDeadlocks() throws Exception { - new Deadlock(); - String s = null; - while (true) { - s = TimedOutTestsListener.buildDeadlockInfo(); - if (s != null) { - break; - } - Thread.sleep(100); - } - - Assert.assertEquals(3, countStringOccurrences(s, "BLOCKED")); - - Failure failure = new Failure(null, new Exception(TimedOutTestsListener.TEST_TIMED_OUT_PREFIX)); - StringWriter writer = new StringWriter(); - new TimedOutTestsListener(new PrintWriter(writer)).testFailure(failure); - String out = writer.toString(); - - Assert.assertTrue(out.contains("THREAD DUMP")); - Assert.assertTrue(out.contains("DEADLOCKS DETECTED")); - - System.out.println(out); - } - - private int countStringOccurrences(String s, String substr) { - int n = 0; - int index = 0; - while ((index = s.indexOf(substr, index) + 1) != 0) { - n++; - } - return n; - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TimedOutTestsListener.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TimedOutTestsListener.java deleted file mode 100644 index e6f8fe4482a..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TimedOutTestsListener.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.testing.util; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.management.LockInfo; -import java.lang.management.ManagementFactory; -import java.lang.management.MonitorInfo; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Map; -import org.apache.commons.lang.StringUtils; -import org.junit.runner.notification.Failure; -import org.junit.runner.notification.RunListener; - -/** - * JUnit run listener which prints full thread dump into System.err in case a test is failed due to - * timeout. - */ -public class TimedOutTestsListener extends RunListener { - - static final String TEST_TIMED_OUT_PREFIX = "test timed out after"; - - private static String indent = " "; - - private final PrintWriter output; - - public TimedOutTestsListener() { - this.output = new PrintWriter(System.err); - } - - public TimedOutTestsListener(PrintWriter output) { - this.output = output; - } - - @Override - public void testFailure(Failure failure) throws Exception { - if (failure != null && failure.getMessage() != null && failure.getMessage().startsWith(TEST_TIMED_OUT_PREFIX)) { - output.println("====> TEST TIMED OUT. PRINTING THREAD DUMP. <===="); - output.println(); - output.print(buildThreadDiagnosticString()); - } - } - - public static String buildThreadDiagnosticString() { - StringWriter sw = new StringWriter(); - PrintWriter output = new PrintWriter(sw); - - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss,SSS"); - output.println(String.format("Timestamp: %s", dateFormat.format(new Date()))); - output.println(); - output.println(buildThreadDump()); - - String deadlocksInfo = buildDeadlockInfo(); - if (deadlocksInfo != null) { - output.println("====> DEADLOCKS DETECTED <===="); - output.println(); - output.println(deadlocksInfo); - } - - return sw.toString(); - } - - static String buildThreadDump() { - StringBuilder dump = new StringBuilder(); - Map stackTraces = Thread.getAllStackTraces(); - for (Map.Entry e : stackTraces.entrySet()) { - Thread thread = e.getKey(); - dump.append(String.format("\"%s\" %s prio=%d tid=%d %s\njava.lang.Thread.State: %s", thread.getName(), - (thread.isDaemon() ? "daemon" : ""), thread.getPriority(), thread.getId(), - Thread.State.WAITING.equals(thread.getState()) ? "in Object.wait()" - : StringUtils.lowerCase(thread.getState().name()), - Thread.State.WAITING.equals(thread.getState()) ? "WAITING (on object monitor)" : thread.getState())); - for (StackTraceElement stackTraceElement : e.getValue()) { - dump.append("\n at "); - dump.append(stackTraceElement); - } - dump.append("\n"); - } - return dump.toString(); - } - - static String buildDeadlockInfo() { - ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); - long[] threadIds = threadBean.findMonitorDeadlockedThreads(); - if (threadIds != null && threadIds.length > 0) { - StringWriter stringWriter = new StringWriter(); - PrintWriter out = new PrintWriter(stringWriter); - - ThreadInfo[] infos = threadBean.getThreadInfo(threadIds, true, true); - for (ThreadInfo ti : infos) { - printThreadInfo(ti, out); - printLockInfo(ti.getLockedSynchronizers(), out); - out.println(); - } - - out.close(); - return stringWriter.toString(); - } else { - return null; - } - } - - private static void printThreadInfo(ThreadInfo ti, PrintWriter out) { - // print thread information - printThread(ti, out); - - // print stack trace with locks - StackTraceElement[] stacktrace = ti.getStackTrace(); - MonitorInfo[] monitors = ti.getLockedMonitors(); - for (int i = 0; i < stacktrace.length; i++) { - StackTraceElement ste = stacktrace[i]; - out.println(indent + "at " + ste.toString()); - for (MonitorInfo mi : monitors) { - if (mi.getLockedStackDepth() == i) { - out.println(indent + " - locked " + mi); - } - } - } - out.println(); - } - - private static void printThread(ThreadInfo ti, PrintWriter out) { - out.print("\"" + ti.getThreadName() + "\"" + " Id=" + ti.getThreadId() + " in " + ti.getThreadState()); - if (ti.getLockName() != null) { - out.print(" on lock=" + ti.getLockName()); - } - if (ti.isSuspended()) { - out.print(" (suspended)"); - } - if (ti.isInNative()) { - out.print(" (running in native)"); - } - out.println(); - if (ti.getLockOwnerName() != null) { - out.println(indent + " owned by " + ti.getLockOwnerName() + " Id=" + ti.getLockOwnerId()); - } - } - - private static void printLockInfo(LockInfo[] locks, PrintWriter out) { - out.println(indent + "Locked synchronizers: count = " + locks.length); - for (LockInfo li : locks) { - out.println(indent + " - " + li); - } - out.println(); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/package-info.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/package-info.java deleted file mode 100644 index 310961d6671..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -/** - * Common testing related utils. - */ -package org.apache.bookkeeper.common.testing.util; \ No newline at end of file diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MemoryLimitControllerTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MemoryLimitControllerTest.java deleted file mode 100644 index 2d81f62f927..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MemoryLimitControllerTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Tests for {@link MemoryLimitController}. - */ -public class MemoryLimitControllerTest { - - private ExecutorService executor; - - @Before - public void setup() { - executor = Executors.newCachedThreadPool(); - } - - @After - public void teardown() { - executor.shutdownNow(); - } - - @Test - public void testLimit() throws Exception { - MemoryLimitController mlc = new MemoryLimitController(100); - - for (int i = 0; i < 101; i++) { - mlc.reserveMemory(1); - } - - assertEquals(101, mlc.currentUsage()); - assertFalse(mlc.tryReserveMemory(1)); - mlc.releaseMemory(1); - assertEquals(100, mlc.currentUsage()); - - assertTrue(mlc.tryReserveMemory(1)); - assertEquals(101, mlc.currentUsage()); - } - - @Test - public void testBlocking() throws Exception { - MemoryLimitController mlc = new MemoryLimitController(100); - - for (int i = 0; i < 101; i++) { - mlc.reserveMemory(1); - } - - CountDownLatch l1 = new CountDownLatch(1); - executor.submit(() -> { - try { - mlc.reserveMemory(1); - l1.countDown(); - } catch (InterruptedException e) { - } - }); - - CountDownLatch l2 = new CountDownLatch(1); - executor.submit(() -> { - try { - mlc.reserveMemory(1); - l2.countDown(); - } catch (InterruptedException e) { - } - }); - - CountDownLatch l3 = new CountDownLatch(1); - executor.submit(() -> { - try { - mlc.reserveMemory(1); - l3.countDown(); - } catch (InterruptedException e) { - } - }); - - // The threads are blocked since the quota is full - assertFalse(l1.await(100, TimeUnit.MILLISECONDS)); - assertFalse(l2.await(100, TimeUnit.MILLISECONDS)); - assertFalse(l3.await(100, TimeUnit.MILLISECONDS)); - - assertEquals(101, mlc.currentUsage()); - mlc.releaseMemory(3); - - assertTrue(l1.await(1, TimeUnit.SECONDS)); - assertTrue(l2.await(1, TimeUnit.SECONDS)); - assertTrue(l3.await(1, TimeUnit.SECONDS)); - assertEquals(101, mlc.currentUsage()); - } - - @Test - public void testStepRelease() throws Exception { - MemoryLimitController mlc = new MemoryLimitController(100); - - for (int i = 0; i < 101; i++) { - mlc.reserveMemory(1); - } - - CountDownLatch l1 = new CountDownLatch(1); - executor.submit(() -> { - try { - mlc.reserveMemory(1); - l1.countDown(); - } catch (InterruptedException e) { - } - }); - - CountDownLatch l2 = new CountDownLatch(1); - executor.submit(() -> { - try { - mlc.reserveMemory(1); - l2.countDown(); - } catch (InterruptedException e) { - } - }); - - CountDownLatch l3 = new CountDownLatch(1); - executor.submit(() -> { - try { - mlc.reserveMemory(1); - l3.countDown(); - } catch (InterruptedException e) { - } - }); - - // The threads are blocked since the quota is full - assertFalse(l1.await(100, TimeUnit.MILLISECONDS)); - assertFalse(l2.await(100, TimeUnit.MILLISECONDS)); - assertFalse(l3.await(100, TimeUnit.MILLISECONDS)); - - assertEquals(101, mlc.currentUsage()); - - mlc.releaseMemory(1); - mlc.releaseMemory(1); - mlc.releaseMemory(1); - - assertTrue(l1.await(1, TimeUnit.SECONDS)); - assertTrue(l2.await(1, TimeUnit.SECONDS)); - assertTrue(l3.await(1, TimeUnit.SECONDS)); - assertEquals(101, mlc.currentUsage()); - } -} \ No newline at end of file diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MockTicker.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MockTicker.java deleted file mode 100644 index 3df980fb759..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MockTicker.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import com.google.common.base.Ticker; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Test implementation of Ticker. - */ -public class MockTicker extends Ticker { - private AtomicLong tick = new AtomicLong(0); - - public void advance(int period, TimeUnit unit) { - tick.addAndGet(unit.toNanos(period)); - } - - @Override - public long read() { - return tick.get(); - } -} - - diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestBackoff.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestBackoff.java deleted file mode 100644 index b35fcc06058..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestBackoff.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.apache.bookkeeper.common.util.Backoff.Jitter.Type.DECORRELATED; -import static org.apache.bookkeeper.common.util.Backoff.Jitter.Type.EQUAL; -import static org.apache.bookkeeper.common.util.Backoff.Jitter.Type.EXPONENTIAL; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Iterator; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.LongStream; -import java.util.stream.Stream; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Test; - -/** - * Unit test for {@link Backoff}. - */ -public class TestBackoff { - - static void assertStreamEquals(Stream s1, Stream s2) { - Iterator iter1 = s1.iterator(), iter2 = s2.iterator(); - while (iter1.hasNext() && iter2.hasNext()) { - T expectedValue = iter1.next(); - T actualValue = iter2.next(); - assertEquals("Expected = " + expectedValue + ", Actual = " + actualValue, - expectedValue, actualValue); - } - assertTrue(!iter1.hasNext() && !iter2.hasNext()); - } - - @Test - public void testExponential() throws Exception { - Stream backoffs = Backoff.exponential(1000, 2, Long.MAX_VALUE).limit(10); - Stream expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> (1000L << i)); - assertStreamEquals(expectedBackoffs, backoffs); - } - - @Test - public void testExponentialPolicy() throws Exception { - Stream expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> (1000L << i)); - Backoff.Policy policy = Backoff.Exponential.of(1000, Long.MAX_VALUE, 2, 10); - assertStreamEquals(expectedBackoffs, policy.toBackoffs()); - } - - @Test - public void testExponentialWithUpperLimit() throws Exception { - Stream backoffs = Backoff.exponential(1000, 2, 32000).limit(10); - Stream expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> Math.min(1000L << i, 32000)); - assertStreamEquals(expectedBackoffs, backoffs); - } - - @Test - public void testExponentialPolicyWithUpperLimit() throws Exception { - Stream expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> Math.min(1000L << i, 32000)); - Backoff.Policy policy = Backoff.Exponential.of(1000, 32000, 2, 10); - assertStreamEquals(expectedBackoffs, policy.toBackoffs()); - } - - @Test - public void testExponentialJittered() throws Exception { - Stream backoffs = Backoff.exponentialJittered(5, 120).limit(10); - // Expected: 5, then randos up to: 10, 20, 40, 80, 120, 120, 120 ... - Stream maxBackoffs = Stream.of(5L, 10L, 20L, 40L, 80L, 120L, 120L, 120L, 120L, 120L); - StreamUtil.zip(backoffs, maxBackoffs, (expected, actual) -> { - assertTrue(expected <= actual); - return null; - }); - } - - @Test - public void testExponentialJitteredPolicy() throws Exception { - Stream backoffs = Backoff.Jitter.of(EXPONENTIAL, 5, 120, 10).toBackoffs(); - // Expected: 5, then randos up to: 10, 20, 40, 80, 120, 120, 120 ... - Stream maxBackoffs = Stream.of(5L, 10L, 20L, 40L, 80L, 120L, 120L, 120L, 120L, 120L); - StreamUtil.zip(backoffs, maxBackoffs, (expected, actual) -> { - assertTrue(expected <= actual); - return null; - }); - } - - @Test - public void testConstant() throws Exception { - Stream backoffs = Backoff.constant(12345L).limit(10); - Stream expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> 12345L); - assertStreamEquals(expectedBackoffs, backoffs); - } - - @Test - public void testConstantPolicy() throws Exception { - Stream backoffs = Backoff.Constant.of(12345L, 10).toBackoffs(); - Stream expectedBackoffs = LongStream.range(0L, 10L).mapToObj(i -> 12345L); - assertStreamEquals(expectedBackoffs, backoffs); - } - - @Test - public void testEqualJittered() throws Exception { - Stream backoffs = Backoff.equalJittered(5, 120).limit(10); - Stream> ranges = Stream.of( - Pair.of(5L, 10L), - Pair.of(10L, 20L), - Pair.of(20L, 40L), - Pair.of(40L, 80L), - Pair.of(80L, 120L), - Pair.of(80L, 120L), - Pair.of(80L, 120L), - Pair.of(80L, 120L), - Pair.of(80L, 120L) - ); - StreamUtil., Void>zip(backoffs, ranges, (backoff, maxPair) -> { - assertTrue(backoff >= maxPair.getLeft()); - assertTrue(backoff <= maxPair.getRight()); - return null; - }); - } - - @Test - public void testEqualJitteredPolicy() throws Exception { - Stream backoffs = Backoff.Jitter.of(EQUAL, 5, 120, 10).toBackoffs(); - Stream> ranges = Stream.of( - Pair.of(5L, 10L), - Pair.of(10L, 20L), - Pair.of(20L, 40L), - Pair.of(40L, 80L), - Pair.of(80L, 120L), - Pair.of(80L, 120L), - Pair.of(80L, 120L), - Pair.of(80L, 120L), - Pair.of(80L, 120L) - ); - StreamUtil., Void>zip(backoffs, ranges, (backoff, maxPair) -> { - assertTrue(backoff >= maxPair.getLeft()); - assertTrue(backoff <= maxPair.getRight()); - return null; - }); - } - - @Test - public void testDecorrelatedJittered() throws Exception { - long startMs = ThreadLocalRandom.current().nextLong(1L, 1000L); - long maxMs = ThreadLocalRandom.current().nextLong(startMs, startMs * 2); - Stream backoffs = Backoff.decorrelatedJittered(startMs, maxMs).limit(10); - Iterator backoffIter = backoffs.iterator(); - assertTrue(backoffIter.hasNext()); - assertEquals(startMs, backoffIter.next().longValue()); - AtomicLong prevMs = new AtomicLong(startMs); - backoffIter.forEachRemaining(backoffMs -> { - assertTrue(backoffMs >= startMs); - assertTrue(backoffMs <= prevMs.get() * 3); - assertTrue(backoffMs <= maxMs); - prevMs.set(backoffMs); - }); - } - - @Test - public void testDecorrelatedJitteredPolicy() throws Exception { - long startMs = ThreadLocalRandom.current().nextLong(1L, 1000L); - long maxMs = ThreadLocalRandom.current().nextLong(startMs, startMs * 2); - Stream backoffs = Backoff.Jitter.of(DECORRELATED, startMs, maxMs, 10).toBackoffs(); - Iterator backoffIter = backoffs.iterator(); - assertTrue(backoffIter.hasNext()); - assertEquals(startMs, backoffIter.next().longValue()); - AtomicLong prevMs = new AtomicLong(startMs); - backoffIter.forEachRemaining(backoffMs -> { - assertTrue(backoffMs >= startMs); - assertTrue(backoffMs <= prevMs.get() * 3); - assertTrue(backoffMs <= maxMs); - prevMs.set(backoffMs); - }); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestMathUtils.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestMathUtils.java deleted file mode 100644 index fc2318b9392..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestMathUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.apache.bookkeeper.common.util.MathUtils.findNextPositivePowerOfTwo; -import static org.apache.bookkeeper.common.util.MathUtils.nowInNano; -import static org.apache.bookkeeper.common.util.MathUtils.signSafeMod; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test of {@link MathUtils}. - */ -public class TestMathUtils { - - @Test - public void testSignSafeMod() { - assertEquals(1, signSafeMod(11, 2)); - assertEquals(1, signSafeMod(-11, 2)); - assertEquals(1, signSafeMod(11, -2)); - assertEquals(-3, signSafeMod(-11, -2)); - } - - @Test - public void testFindNextPositivePowerOfTwo() { - assertEquals(16384, findNextPositivePowerOfTwo(12345)); - } - - @Test - public void testNowInNanos() { - long nowInNanos = nowInNano(); - assertTrue(System.nanoTime() >= nowInNanos); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestOrderedExecutorDecorators.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestOrderedExecutorDecorators.java deleted file mode 100644 index 5d83369fe3b..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestOrderedExecutorDecorators.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.common.util; - -import static org.hamcrest.Matchers.hasItem; -import static org.junit.Assert.assertThat; -import static org.mockito.AdditionalAnswers.answerVoid; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; - -import java.util.Queue; -import java.util.UUID; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.TimeUnit; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.NullAppender; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test that decorators applied by OrderedExecutor/Scheduler are correctly applied. - */ -public class TestOrderedExecutorDecorators { - private static final Logger log = LoggerFactory.getLogger(TestOrderedExecutorDecorators.class); - private static final String MDC_KEY = "mdc-key"; - - private NullAppender mockAppender; - private final Queue capturedEvents = new ConcurrentLinkedQueue<>(); - - public static String mdcFormat(Object mdc, String message) { - return String.format("[%s:%s] %s", MDC_KEY, mdc, message); - } - - @Before - public void setUp() throws Exception { - ThreadContext.clearMap(); - LoggerContext lc = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); - mockAppender = spy(NullAppender.createAppender(UUID.randomUUID().toString())); - mockAppender.start(); - lc.getConfiguration().addAppender(mockAppender); - lc.getRootLogger().addAppender(lc.getConfiguration().getAppender(mockAppender.getName())); - lc.getConfiguration().getRootLogger().setLevel(Level.INFO); - lc.updateLoggers(); - - doAnswer(answerVoid((LogEvent event) -> { - capturedEvents.add(mdcFormat(event.getContextData().getValue(MDC_KEY), - event.getMessage().getFormattedMessage())); - })).when(mockAppender).append(any()); - } - - @After - public void tearDown() throws Exception { - LoggerContext lc = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); - lc.getRootLogger().removeAppender(lc.getConfiguration().getAppender(mockAppender.getName())); - lc.updateLoggers(); - capturedEvents.clear(); - ThreadContext.clearMap(); - } - - @Test - public void testMDCInvokeOrdered() throws Exception { - OrderedExecutor executor = OrderedExecutor.newBuilder() - .name("test").numThreads(20).preserveMdcForTaskExecution(true).build(); - - try { - ThreadContext.put(MDC_KEY, "testMDCInvokeOrdered"); - executor.submitOrdered(10, () -> { - log.info("foobar"); - return 10; - }).get(); - assertThat(capturedEvents, - hasItem(mdcFormat("testMDCInvokeOrdered", "foobar"))); - } finally { - executor.shutdown(); - } - } - - @Test - public void testMDCInvokeDirectOnChosen() throws Exception { - OrderedExecutor executor = OrderedExecutor.newBuilder() - .name("test").numThreads(20).preserveMdcForTaskExecution(true).build(); - - try { - ThreadContext.put(MDC_KEY, "testMDCInvokeOrdered"); - executor.chooseThread(10).submit(() -> { - log.info("foobar"); - return 10; - }).get(); - assertThat(capturedEvents, - hasItem(mdcFormat("testMDCInvokeOrdered", "foobar"))); - } finally { - executor.shutdown(); - } - - } - - - @Test - public void testMDCScheduleOrdered() throws Exception { - OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test").numThreads(20).preserveMdcForTaskExecution(true).build(); - - try { - ThreadContext.put(MDC_KEY, "testMDCInvokeOrdered"); - scheduler.scheduleOrdered(10, () -> log.info("foobar"), 0, TimeUnit.DAYS).get(); - assertThat(capturedEvents, - hasItem(mdcFormat("testMDCInvokeOrdered", "foobar"))); - } finally { - scheduler.shutdown(); - } - } - - @Test - public void testMDCScheduleDirectOnChosen() throws Exception { - OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test").numThreads(20).preserveMdcForTaskExecution(true).build(); - - try { - ThreadContext.put(MDC_KEY, "testMDCInvokeOrdered"); - scheduler.chooseThread(10).schedule(() -> log.info("foobar"), 0, TimeUnit.DAYS).get(); - assertThat(capturedEvents, - hasItem(mdcFormat("testMDCInvokeOrdered", "foobar"))); - } finally { - scheduler.shutdown(); - } - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestReflectionUtils.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestReflectionUtils.java deleted file mode 100644 index dd1535fa2ce..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestReflectionUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.apache.bookkeeper.common.util.ReflectionUtils.forName; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.junit.Test; - -/** - * Unit test of {@link ReflectionUtils}. - */ -public class TestReflectionUtils { - - interface InterfaceA { - } - - interface InterfaceB { - } - - private static class ClassA implements InterfaceA { - } - - private static class ClassB implements InterfaceB { - } - - @Test - public void testForNameClassNotFound() { - try { - forName( - "test.for.name.class.not.found", - Object.class); - fail("Should fail if class not found"); - } catch (RuntimeException re) { - assertTrue(re.getCause() instanceof ClassNotFoundException); - } - } - - @Test - public void testForNameUnassignable() { - try { - forName( - ClassA.class.getName(), - InterfaceB.class); - fail("Should fail if class is not assignable"); - } catch (RuntimeException re) { - assertEquals( - ClassA.class.getName() + " not " + InterfaceB.class.getName(), - re.getMessage()); - } - } - - @Test - public void testForName() throws Exception { - Class theCls = forName( - ClassB.class.getName(), - InterfaceB.class); - assertEquals(ClassB.class, theCls); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSharedResourceManager.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSharedResourceManager.java deleted file mode 100644 index fab622f0c7b..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSharedResourceManager.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.LinkedList; -import java.util.concurrent.Delayed; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import org.apache.bookkeeper.common.util.SharedResourceManager.Resource; -import org.junit.Before; -import org.junit.Test; -import org.mockito.stubbing.Answer; - -/** - * Unit test for {@link SharedResourceManager}. - */ -public class TestSharedResourceManager { - - private final LinkedList> scheduledDestroyTasks = - new LinkedList<>(); - - private SharedResourceManager manager; - - private static class ResourceInstance { - volatile boolean closed; - } - - private static class ResourceFactory implements Resource { - @Override - public ResourceInstance create() { - return new ResourceInstance(); - } - - @Override - public void close(ResourceInstance instance) { - instance.closed = true; - } - } - - // Defines two kinds of resources - private static final Resource SHARED_FOO = new ResourceFactory(); - private static final Resource SHARED_BAR = new ResourceFactory(); - - @Before - public void setUp() { - manager = SharedResourceManager.create(new MockExecutorFactory()); - } - - @Test - public void destroyResourceWhenRefCountReachesZero() { - ResourceInstance foo1 = manager.get(SHARED_FOO); - ResourceInstance sharedFoo = foo1; - ResourceInstance foo2 = manager.get(SHARED_FOO); - assertSame(sharedFoo, foo2); - - ResourceInstance bar1 = manager.get(SHARED_BAR); - ResourceInstance sharedBar = bar1; - - manager.release(SHARED_FOO, foo2); - // foo refcount not reached 0, thus shared foo is not closed - assertTrue(scheduledDestroyTasks.isEmpty()); - assertFalse(sharedFoo.closed); - - manager.release(SHARED_FOO, foo1); - - // foo refcount has reached 0, a destroying task is scheduled - assertEquals(1, scheduledDestroyTasks.size()); - MockScheduledFuture scheduledDestroyTask = scheduledDestroyTasks.poll(); - assertEquals(SharedResourceManager.DESTROY_DELAY_SECONDS, - scheduledDestroyTask.getDelay(TimeUnit.SECONDS)); - - // Simluate that the destroyer executes the foo destroying task - scheduledDestroyTask.runTask(); - assertTrue(sharedFoo.closed); - - // After the destroying, obtaining a foo will get a different instance - ResourceInstance foo3 = manager.get(SHARED_FOO); - assertNotSame(sharedFoo, foo3); - - manager.release(SHARED_BAR, bar1); - - // bar refcount has reached 0, a destroying task is scheduled - assertEquals(1, scheduledDestroyTasks.size()); - scheduledDestroyTask = scheduledDestroyTasks.poll(); - assertEquals(SharedResourceManager.DESTROY_DELAY_SECONDS, - scheduledDestroyTask.getDelay(TimeUnit.SECONDS)); - - // Simulate that the destroyer executes the bar destroying task - scheduledDestroyTask.runTask(); - assertTrue(sharedBar.closed); - } - - @Test - public void cancelDestroyTask() { - ResourceInstance foo1 = manager.get(SHARED_FOO); - ResourceInstance sharedFoo = foo1; - manager.release(SHARED_FOO, foo1); - // A destroying task for foo is scheduled - MockScheduledFuture scheduledDestroyTask = scheduledDestroyTasks.poll(); - assertFalse(scheduledDestroyTask.cancelled); - - // obtaining a foo before the destroying task is executed will cancel the destroy - ResourceInstance foo2 = manager.get(SHARED_FOO); - assertTrue(scheduledDestroyTask.cancelled); - assertTrue(scheduledDestroyTasks.isEmpty()); - assertFalse(sharedFoo.closed); - - // And it will be the same foo instance - assertSame(sharedFoo, foo2); - - // Release it and the destroying task is scheduled again - manager.release(SHARED_FOO, foo2); - scheduledDestroyTask = scheduledDestroyTasks.poll(); - assertFalse(scheduledDestroyTask.cancelled); - scheduledDestroyTask.runTask(); - assertTrue(sharedFoo.closed); - } - - @Test - public void releaseWrongInstance() { - ResourceInstance uncached = new ResourceInstance(); - try { - manager.release(SHARED_FOO, uncached); - fail("Should throw IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } - ResourceInstance cached = manager.get(SHARED_FOO); - try { - manager.release(SHARED_FOO, uncached); - fail("Should throw IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } - manager.release(SHARED_FOO, cached); - } - - @Test - public void overreleaseInstance() { - ResourceInstance foo1 = manager.get(SHARED_FOO); - manager.release(SHARED_FOO, foo1); - try { - manager.release(SHARED_FOO, foo1); - fail("Should throw IllegalStateException"); - } catch (IllegalStateException e) { - // expected - } - } - - private class MockExecutorFactory implements Supplier { - @Override - public ScheduledExecutorService get() { - ScheduledExecutorService mockExecutor = mock(ScheduledExecutorService.class); - when(mockExecutor.schedule(any(Runnable.class), anyLong(), any(TimeUnit.class))).thenAnswer( - (Answer>) invocation -> { - Object[] args = invocation.getArguments(); - Runnable command = (Runnable) args[0]; - long delay = (Long) args[1]; - TimeUnit unit = (TimeUnit) args[2]; - MockScheduledFuture future = new MockScheduledFuture( - command, delay, unit); - scheduledDestroyTasks.add(future); - return future; - }); - return mockExecutor; - } - } - - private static class MockScheduledFuture implements ScheduledFuture { - private boolean cancelled; - private boolean finished; - final Runnable command; - final long delay; - final TimeUnit unit; - - MockScheduledFuture(Runnable command, long delay, TimeUnit unit) { - this.command = command; - this.delay = delay; - this.unit = unit; - } - - void runTask() { - command.run(); - finished = true; - } - - @Override - public boolean cancel(boolean interrupt) { - if (cancelled || finished) { - return false; - } - cancelled = true; - return true; - } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public long getDelay(TimeUnit targetUnit) { - return targetUnit.convert(this.delay, this.unit); - } - - @Override - public int compareTo(Delayed o) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isDone() { - return cancelled || finished; - } - - @Override - public V get() { - throw new UnsupportedOperationException(); - } - - @Override - public V get(long timeout, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSingleThreadExecutor.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSingleThreadExecutor.java deleted file mode 100644 index 671318de6e2..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSingleThreadExecutor.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.util.concurrent.DefaultThreadFactory; -import java.util.List; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import lombok.Cleanup; -import org.awaitility.Awaitility; -import org.junit.Test; - -/** - * Unit test for {@link SingleThreadExecutor}. - */ -public class TestSingleThreadExecutor { - - private static final ThreadFactory THREAD_FACTORY = new DefaultThreadFactory("test"); - - @Test - public void testSimple() throws Exception { - @Cleanup("shutdown") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY); - - AtomicInteger count = new AtomicInteger(); - - assertEquals(0, ste.getSubmittedTasksCount()); - assertEquals(0, ste.getCompletedTasksCount()); - assertEquals(0, ste.getQueuedTasksCount()); - - for (int i = 0; i < 10; i++) { - ste.execute(() -> count.incrementAndGet()); - } - - assertEquals(10, ste.getSubmittedTasksCount()); - - ste.submit(() -> { - }).get(); - - assertEquals(10, count.get()); - assertEquals(11, ste.getSubmittedTasksCount()); - - Awaitility.await().untilAsserted(() -> assertEquals(11, ste.getCompletedTasksCount())); - assertEquals(0, ste.getRejectedTasksCount()); - assertEquals(0, ste.getFailedTasksCount()); - assertEquals(0, ste.getQueuedTasksCount()); - } - - @Test - public void testRejectWhenQueueIsFull() throws Exception { - @Cleanup("shutdownNow") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY, 10, true); - - CyclicBarrier barrier = new CyclicBarrier(10 + 1); - CountDownLatch startedLatch = new CountDownLatch(1); - - for (int i = 0; i < 10; i++) { - ste.execute(() -> { - startedLatch.countDown(); - - try { - barrier.await(); - } catch (InterruptedException | BrokenBarrierException e) { - // ignore - } - }); - - // Wait until the first task is already running in the thread - startedLatch.await(); - } - - // Next task should go through, because the runner thread has already pulled out 1 item from the - // queue: the first tasks which is currently stuck - ste.execute(() -> { - }); - - // Now the queue is really full and should reject tasks - try { - ste.execute(() -> { - }); - fail("should have rejected the task"); - } catch (RejectedExecutionException e) { - // Expected - } - - assertTrue(ste.getSubmittedTasksCount() >= 11); - assertTrue(ste.getRejectedTasksCount() >= 1); - assertEquals(0, ste.getFailedTasksCount()); - } - - @Test - public void testBlockWhenQueueIsFull() throws Exception { - @Cleanup("shutdown") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY, 10, false); - - CyclicBarrier barrier = new CyclicBarrier(10 + 1); - - for (int i = 0; i < 10; i++) { - ste.execute(() -> { - try { - barrier.await(1, TimeUnit.SECONDS); - } catch (TimeoutException te) { - // ignore - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } - - assertEquals(10, ste.getQueuedTasksCount()); - - ste.submit(() -> { - }).get(); - - assertEquals(11, ste.getSubmittedTasksCount()); - assertEquals(0, ste.getRejectedTasksCount()); - } - - @Test - public void testShutdown() throws Exception { - @Cleanup("shutdown") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY); - - assertFalse(ste.isShutdown()); - assertFalse(ste.isTerminated()); - - AtomicInteger count = new AtomicInteger(); - - for (int i = 0; i < 3; i++) { - ste.execute(() -> { - try { - Thread.sleep(1000); - count.incrementAndGet(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); - } - - ste.shutdown(); - assertTrue(ste.isShutdown()); - assertFalse(ste.isTerminated()); - - try { - ste.execute(() -> { - }); - fail("should have rejected the task"); - } catch (RejectedExecutionException e) { - // Expected - } - - ste.awaitTermination(10, TimeUnit.SECONDS); - assertTrue(ste.isShutdown()); - assertTrue(ste.isTerminated()); - - assertEquals(3, count.get()); - } - - @Test - public void testShutdownNow() throws Exception { - @Cleanup("shutdown") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY); - - assertFalse(ste.isShutdown()); - assertFalse(ste.isTerminated()); - - AtomicInteger count = new AtomicInteger(); - - for (int i = 0; i < 3; i++) { - ste.execute(() -> { - try { - Thread.sleep(2000); - count.incrementAndGet(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); - - // Ensure the 3 tasks are not picked up in one shot by the runner thread - Thread.sleep(500); - } - - List remainingTasks = ste.shutdownNow(); - assertEquals(2, remainingTasks.size()); - assertTrue(ste.isShutdown()); - - try { - ste.execute(() -> { - }); - fail("should have rejected the task"); - } catch (RejectedExecutionException e) { - // Expected - } - - ste.awaitTermination(10, TimeUnit.SECONDS); - assertTrue(ste.isShutdown()); - assertTrue(ste.isTerminated()); - - assertEquals(0, count.get()); - } - - @Test - public void testTasksWithException() throws Exception { - @Cleanup("shutdown") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY); - - AtomicInteger count = new AtomicInteger(); - - for (int i = 0; i < 10; i++) { - ste.execute(() -> { - count.incrementAndGet(); - throw new RuntimeException("xyz"); - }); - } - - ste.submit(() -> { - }).get(); - assertEquals(10, count.get()); - - assertEquals(11, ste.getSubmittedTasksCount()); - Awaitility.await().untilAsserted(() -> assertEquals(1, ste.getCompletedTasksCount())); - assertEquals(0, ste.getRejectedTasksCount()); - assertEquals(10, ste.getFailedTasksCount()); - } - - @Test - public void testTasksWithNPE() throws Exception { - @Cleanup("shutdown") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY); - - AtomicInteger count = new AtomicInteger(); - String npeTest = null; - - for (int i = 0; i < 10; i++) { - ste.execute(() -> { - count.incrementAndGet(); - - // Trigger the NPE exception - System.out.println(npeTest.length()); - }); - } - - ste.submit(() -> { - }).get(); - assertEquals(10, count.get()); - - assertEquals(11, ste.getSubmittedTasksCount()); - Awaitility.await().untilAsserted(() -> assertEquals(1, ste.getCompletedTasksCount())); - assertEquals(0, ste.getRejectedTasksCount()); - assertEquals(10, ste.getFailedTasksCount()); - } - - @Test - public void testShutdownEmpty() throws Exception { - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY); - ste.shutdown(); - assertTrue(ste.isShutdown()); - - ste.awaitTermination(10, TimeUnit.SECONDS); - assertTrue(ste.isShutdown()); - assertTrue(ste.isTerminated()); - } - - @Test - public void testExecutorQueueIsNotFixedSize() throws Exception { - int n = 1_000_000; - @Cleanup("shutdown") - SingleThreadExecutor ste = new SingleThreadExecutor(THREAD_FACTORY); - - CountDownLatch latch = new CountDownLatch(1); - // First task is blocking - ste.execute(() -> { - try { - latch.await(); - } catch (Exception e) { - e.printStackTrace(); - } - }); - - for (int i = 0; i < n; i++) { - ste.execute(() -> {}); - } - - // Submit last task and wait for completion - Future future = ste.submit(() -> {}); - - latch.countDown(); - - future.get(); - } -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestThreadSelection.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestThreadSelection.java deleted file mode 100644 index 72b48b0f205..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestThreadSelection.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.common.util; - -import com.google.common.primitives.Longs; -import java.security.SecureRandom; -import java.util.Random; -import lombok.extern.slf4j.Slf4j; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test how even is the distribution of ledgers across the threads of OrderedExecutor. - */ -@Slf4j -public class TestThreadSelection { - - public static final long MAX_KEY = 1_000_000L; - public static final int MAX_THREADS = 96; - public static final double MAX_DISPARITY = 1.25d; - - private final Random rnd = new SecureRandom(); - - /** - * Only even keys. - */ - @Test - public void testThreadSelectionEvenKeys() { - runTest(0L, 2L); - } - - /** - * Only odd keys. - */ - @Test - public void testThreadSelectionOddKeys() { - runTest(1L, 2L); - } - - /** - * All keys. - */ - @Test - public void testThreadSelectionAllKeys() { - runTest(0L, 1L); - } - - /** - * Random keys. - */ - @Test - public void testThreadSelectionRandKeys() { - for (int numThreads = 2; numThreads <= MAX_THREADS; numThreads++) { - long[] placement = new long[numThreads]; - - log.info("testing {} threads", numThreads); - for (long key = 0L; key < MAX_KEY; key += 1L) { - int threadId = OrderedExecutor.chooseThreadIdx(rnd.nextLong(), numThreads); - placement[threadId]++; - } - validateTest(placement, numThreads); - } - } - - /** - * Confirm the same key assigned to the same thread on consequent calls. - */ - @Test - public void testKeyAssignedToTheSameThread() { - for (int numThreads = 2; numThreads <= MAX_THREADS; numThreads++) { - - log.info("testing {} threads", numThreads); - for (long key = 0L; key < MAX_KEY; key += 1L) { - int threadId = OrderedExecutor.chooseThreadIdx(key, numThreads); - for (int i = 0; i < 10; i++) { - Assert.assertEquals("must be assigned to the same thread", - threadId, OrderedExecutor.chooseThreadIdx(key, numThreads)); - } - } - } - } - - - private void runTest(long start, long step) { - for (int numThreads = 2; numThreads <= MAX_THREADS; numThreads++) { - long[] placement = new long[numThreads]; - - log.info("testing {} threads", numThreads); - for (long key = start; key < MAX_KEY; key += step) { - int threadId = OrderedExecutor.chooseThreadIdx(key, numThreads); - placement[threadId]++; - } - validateTest(placement, numThreads); - } - } - - private void validateTest(long[] placement, int numThreads) { - long min = Longs.min(placement); - long max = Longs.max(placement); - log.info("got min={}, max={} (disparity: {}) for {} threads with {} ids", - min, max, max - min, numThreads, MAX_KEY); - Assert.assertTrue("all threads were used [numThreads: " + numThreads + "]", - min > 0); - log.info("disparity = {}", String.format("%,.2f", (double) max / min)); - Assert.assertTrue("no large disparity found [numThreads: " + numThreads + "], got " - + (double) max / min, - (double) max / min <= MAX_DISPARITY); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestWatchable.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestWatchable.java deleted file mode 100644 index 697d0dacd85..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestWatchable.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.function.Function; -import org.apache.bookkeeper.common.collections.RecyclableArrayList.Recycler; -import org.junit.After; -import org.junit.Test; - -/** - * Unit test of {@link Watchable}. - */ -public class TestWatchable { - - private final Recycler> recycler; - private final Watchable watchable; - - public TestWatchable() { - this.recycler = new Recycler<>(); - this.watchable = new Watchable<>(recycler); - } - - @After - public void teardown() { - this.watchable.recycle(); - } - - @Test - @SuppressWarnings("unchecked") - public void testAddWatcher() { - Watcher watcher = mock(Watcher.class); - assertTrue(watchable.addWatcher(watcher)); - assertEquals(1, watchable.getNumWatchers()); - - watchable.notifyWatchers(Function.identity(), 123); - verify(watcher, times(1)).update(eq(123)); - - // after the watcher is fired, watcher should be removed from watcher list. - assertEquals(0, watchable.getNumWatchers()); - } - - @Test - @SuppressWarnings("unchecked") - public void testDeleteWatcher() { - Watcher watcher = mock(Watcher.class); - assertTrue(watchable.addWatcher(watcher)); - assertEquals(1, watchable.getNumWatchers()); - assertTrue(watchable.deleteWatcher(watcher)); - assertEquals(0, watchable.getNumWatchers()); - - watchable.notifyWatchers(Function.identity(), 123); - verify(watcher, times(0)).update(anyInt()); - } - - @Test - @SuppressWarnings("unchecked") - public void testMultipleWatchers() { - Watcher watcher1 = mock(Watcher.class); - Watcher watcher2 = mock(Watcher.class); - - assertTrue(watchable.addWatcher(watcher1)); - assertTrue(watchable.addWatcher(watcher2)); - assertEquals(2, watchable.getNumWatchers()); - - watchable.notifyWatchers(Function.identity(), 123); - verify(watcher1, times(1)).update(eq(123)); - verify(watcher2, times(1)).update(eq(123)); - assertEquals(0, watchable.getNumWatchers()); - } - - @Test - @SuppressWarnings("unchecked") - public void testAddWatchMultipleTimes() { - Watcher watcher = mock(Watcher.class); - - int numTimes = 3; - for (int i = 0; i < numTimes; i++) { - assertTrue(watchable.addWatcher(watcher)); - } - assertEquals(numTimes, watchable.getNumWatchers()); - - watchable.notifyWatchers(Function.identity(), 123); - verify(watcher, times(numTimes)).update(eq(123)); - assertEquals(0, watchable.getNumWatchers()); - } - - @Test - @SuppressWarnings("unchecked") - public void testDeleteWatchers() { - Watcher watcher1 = mock(Watcher.class); - Watcher watcher2 = mock(Watcher.class); - - assertTrue(watchable.addWatcher(watcher1)); - assertTrue(watchable.addWatcher(watcher2)); - assertEquals(2, watchable.getNumWatchers()); - watchable.deleteWatchers(); - assertEquals(0, watchable.getNumWatchers()); - - watchable.notifyWatchers(Function.identity(), 123); - verify(watcher1, times(0)).update(anyInt()); - verify(watcher2, times(0)).update(anyInt()); - } - -} diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/test/TestStatsProvider.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/test/TestStatsProvider.java deleted file mode 100644 index d3299b077e8..00000000000 --- a/bookkeeper-common/src/test/java/org/apache/bookkeeper/test/TestStatsProvider.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.test; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.BiConsumer; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.stats.Gauge; -import org.apache.bookkeeper.stats.OpStatsData; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.stats.StatsProvider; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.lang.StringUtils; - -/** - * Simple in-memory stat provider for use in unit tests. - */ -public class TestStatsProvider implements StatsProvider { - /** - * In-memory counter. - */ - public class TestCounter implements Counter { - private AtomicLong val = new AtomicLong(0); - private AtomicLong max = new AtomicLong(0); - - @Override - public void clear() { - val.set(0); - } - - @Override - public void inc() { - updateMax(val.incrementAndGet()); - } - - @Override - public void dec() { - val.decrementAndGet(); - } - - @Override - public void addCount(long delta) { - updateMax(val.addAndGet(delta)); - } - - @Override - public void addLatency(long eventLatency, TimeUnit unit) { - long valueMillis = unit.toMillis(eventLatency); - updateMax(val.addAndGet(valueMillis)); - } - - @Override - public Long get() { - return val.get(); - } - - private void updateMax(long newVal) { - while (true) { - long curMax = max.get(); - if (curMax > newVal) { - break; - } - if (max.compareAndSet(curMax, newVal)) { - break; - } - } - } - - public Long getMax() { - return max.get(); - } - } - - /** - * In-memory StatsLogger. - */ - public class TestOpStatsLogger implements OpStatsLogger { - private long successCount; - private long successValue; - - private long failureCount; - private long failureValue; - - TestOpStatsLogger() { - clear(); - } - - @Override - public void registerFailedEvent(long eventLatency, TimeUnit unit) { - registerFailedValue(TimeUnit.NANOSECONDS.convert(eventLatency, unit)); - } - - @Override - public void registerSuccessfulEvent(long eventLatency, TimeUnit unit) { - registerSuccessfulValue(TimeUnit.NANOSECONDS.convert(eventLatency, unit)); - } - - @Override - public synchronized void registerSuccessfulValue(long value) { - successCount++; - successValue += value; - } - - @Override - public synchronized void registerFailedValue(long value) { - failureCount++; - failureValue += value; - } - - @Override - public OpStatsData toOpStatsData() { - // Not supported at this time - return null; - } - - @Override - public synchronized void clear() { - successCount = 0; - successValue = 0; - failureCount = 0; - failureValue = 0; - } - - public synchronized double getSuccessAverage() { - if (successCount == 0) { - return 0; - } - return successValue / (double) successCount; - } - - public synchronized long getSuccessCount() { - return successCount; - } - - public synchronized long getFailureCount() { - return failureCount; - } - } - - /** - * In-memory Logger. - */ - public class TestStatsLogger implements StatsLogger { - private String path; - - TestStatsLogger(String path) { - this.path = path; - } - - private String getSubPath(String name) { - if (path.isEmpty()) { - return name; - } else { - return path + "." + name; - } - } - - @Override - public OpStatsLogger getOpStatsLogger(String name) { - return TestStatsProvider.this.getOrCreateOpStatsLogger(getSubPath(name)); - } - - @Override - public Counter getCounter(String name) { - return TestStatsProvider.this.getOrCreateCounter(getSubPath(name)); - } - - public Gauge getGauge(String name) { - return gaugeMap.get(getSubPath(name)); - } - - @Override - public void registerGauge(String name, Gauge gauge) { - TestStatsProvider.this.registerGauge(getSubPath(name), gauge); - } - - @Override - public void unregisterGauge(String name, Gauge gauge) { - TestStatsProvider.this.unregisterGauge(getSubPath(name), gauge); - } - - @Override - public StatsLogger scope(String name) { - return new TestStatsLogger(getSubPath(name)); - } - - @Override - public void removeScope(String name, StatsLogger statsLogger) {} - - @Override - public OpStatsLogger getThreadScopedOpStatsLogger(String name) { - return getOpStatsLogger(name); - } - - @Override - public Counter getThreadScopedCounter(String name) { - return getCounter(name); - } - } - - @Override - public void start(Configuration conf) { - } - - @Override - public void stop() { - } - - private Map opStatLoggerMap = new ConcurrentHashMap<>(); - private Map counterMap = new ConcurrentHashMap<>(); - private Map> gaugeMap = new ConcurrentHashMap<>(); - - @Override - public TestStatsLogger getStatsLogger(String scope) { - return new TestStatsLogger(scope); - } - - public TestOpStatsLogger getOpStatsLogger(String path) { - return opStatLoggerMap.get(path); - } - - public TestCounter getCounter(String path) { - return counterMap.get(path); - } - - public Gauge getGauge(String path) { - return gaugeMap.get(path); - } - - public void forEachOpStatLogger(BiConsumer f) { - for (Map.Entry entry : opStatLoggerMap.entrySet()) { - f.accept(entry.getKey(), entry.getValue()); - } - } - - public void clear() { - for (TestOpStatsLogger logger : opStatLoggerMap.values()) { - logger.clear(); - } - for (TestCounter counter : counterMap.values()) { - counter.clear(); - } - } - - private TestOpStatsLogger getOrCreateOpStatsLogger(String path) { - return opStatLoggerMap.computeIfAbsent( - path, - (String s) -> new TestOpStatsLogger()); - } - - private TestCounter getOrCreateCounter(String path) { - return counterMap.computeIfAbsent( - path, - (String s) -> new TestCounter()); - } - - private void registerGauge(String name, Gauge gauge) { - gaugeMap.put(name, gauge); - } - - private void unregisterGauge(String name, Gauge gauge) { - gaugeMap.remove(name, gauge); - } - - @Override - public String getStatsName(String... statsComponents) { - if (statsComponents.length == 0) { - return ""; - } else if (statsComponents[0].isEmpty()) { - return StringUtils.join(statsComponents, '.', 1, statsComponents.length); - } else { - return StringUtils.join(statsComponents, '.'); - } - } -} diff --git a/bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/JettyHttpServer.java b/bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/JettyHttpServer.java deleted file mode 100644 index 5eb32a196e5..00000000000 --- a/bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/JettyHttpServer.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.http.servlet; - -import java.io.File; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.file.Files; -import java.util.List; -import javax.servlet.Servlet; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.webapp.WebAppContext; - -/** - * Jetty based http server. - **/ - -public class JettyHttpServer { - - private Server jettyServer; - private ContextHandlerCollection contexts; - - public JettyHttpServer(String host, int port){ - this.jettyServer = new Server(new InetSocketAddress(host, port)); - this.contexts = new ContextHandlerCollection(); - this.jettyServer.setHandler(contexts); - } - /** - * Add servlet. - **/ - public void addServlet(String webApp, String contextPath, String pathSpec, List servlets) throws IOException{ - if (servlets == null){ - return; - } - File bookieApi = new File(webApp); - if (!bookieApi.isDirectory()) { - Files.createDirectories(bookieApi.toPath()); - } - WebAppContext webAppBookie = new WebAppContext(bookieApi.getAbsolutePath(), contextPath); - for (Servlet s:servlets) { - webAppBookie.addServlet(new ServletHolder(s), pathSpec); - } - contexts.addHandler(webAppBookie); - } - - /** - * Start jetty server. - **/ - public void startServer() throws Exception{ - jettyServer.start(); - } - - /** - * Stop jetty server. - **/ - public void stopServer() throws Exception{ - jettyServer.stop(); - } -} diff --git a/bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/TestBookieHttpServiceServlet.java b/bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/TestBookieHttpServiceServlet.java deleted file mode 100644 index 0f86cb91ee5..00000000000 --- a/bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/TestBookieHttpServiceServlet.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.http.servlet; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import javax.servlet.Servlet; -import org.apache.bookkeeper.http.NullHttpServiceProvider; -import org.apache.commons.io.IOUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -/** - * Test bookie http service servlet. - **/ -public class TestBookieHttpServiceServlet { - - private JettyHttpServer jettyHttpServer; - private String host = "localhost"; - private int port = 8080; - private BookieServletHttpServer bookieServletHttpServer; - @Before - public void setUp() throws Exception { - this.bookieServletHttpServer = new BookieServletHttpServer(); - this.bookieServletHttpServer.initialize(new NullHttpServiceProvider()); - this.jettyHttpServer = new JettyHttpServer(host, port); - List servlets = new ArrayList<>(); - servlets.add(new BookieHttpServiceServlet()); - jettyHttpServer.addServlet("web/bookie", "/", "/", servlets); - jettyHttpServer.startServer(); - } - - @Test - public void testBookieHeartBeat() throws URISyntaxException, IOException { - assertThat(IOUtils.toString(new URI(String.format("http://%s:%d/heartbeat", host, port)), "UTF-8"), - containsString("OK")); - } - - @After - public void stop() throws Exception{ - jettyHttpServer.stopServer(); - } -} diff --git a/bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpServer.java b/bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpServer.java deleted file mode 100644 index a0c6c4ae69a..00000000000 --- a/bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpServer.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.http.vertx; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.io.Files; -import io.vertx.ext.web.handler.BodyHandler; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import org.apache.bookkeeper.http.HttpRouter; -import org.apache.bookkeeper.http.HttpServer; -import org.apache.bookkeeper.http.HttpServiceProvider; -import org.apache.bookkeeper.http.NullHttpServiceProvider; -import org.apache.bookkeeper.http.service.HeartbeatService; -import org.junit.Test; - -/** - * Unit test {@link VertxHttpServer}. - */ -public class TestVertxHttpServer { - @Test - public void testStartBasicHttpServer() throws Exception { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServiceProvider httpServiceProvider = NullHttpServiceProvider.getInstance(); - httpServer.initialize(httpServiceProvider); - assertTrue(httpServer.startServer(0)); - int port = httpServer.getListeningPort(); - HttpResponse httpResponse = send(getUrl(port, HttpRouter.HEARTBEAT), HttpServer.Method.GET); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - assertEquals(HeartbeatService.HEARTBEAT.trim(), httpResponse.responseBody.trim()); - httpServer.stopServer(); - } - - @Test - public void testStartBasicHttpServerConfigHost() throws Exception { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServiceProvider httpServiceProvider = NullHttpServiceProvider.getInstance(); - httpServer.initialize(httpServiceProvider); - assertTrue(httpServer.startServer(0, "localhost")); - int port = httpServer.getListeningPort(); - HttpResponse httpResponse = send(getUrl(port, HttpRouter.HEARTBEAT), HttpServer.Method.GET); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - assertEquals(HeartbeatService.HEARTBEAT.trim(), httpResponse.responseBody.trim()); - httpServer.stopServer(); - } - - @Test - public void testStartMetricsServiceOnRouterPath() throws Exception { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServiceProvider httpServiceProvider = NullHttpServiceProvider.getInstance(); - httpServer.initialize(httpServiceProvider); - assertTrue(httpServer.startServer(0)); - int port = httpServer.getListeningPort(); - HttpResponse httpResponse = send(getUrl(port, HttpRouter.METRICS), HttpServer.Method.GET); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - httpServer.stopServer(); - } - - @Test - public void testHttpMethods() throws Exception { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServiceProvider httpServiceProvider = NullHttpServiceProvider.getInstance(); - httpServer.initialize(httpServiceProvider); - assertTrue(httpServer.startServer(0)); - int port = httpServer.getListeningPort(); - HttpResponse httpResponse = send(getUrl(port, HttpRouter.GC), HttpServer.Method.GET); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - httpResponse = send(getUrl(port, HttpRouter.GC), HttpServer.Method.POST); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - httpResponse = send(getUrl(port, HttpRouter.GC), HttpServer.Method.PUT); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - httpServer.stopServer(); - } - - @Test - public void testHttpMethodsWithBody() throws IOException { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServiceProvider httpServiceProvider = NullHttpServiceProvider.getInstance(); - httpServer.initialize(httpServiceProvider); - assertTrue(httpServer.startServer(0)); - int port = httpServer.getListeningPort(); - String body = "{\"bookie_src\": \"localhost:3181\"}"; - HttpResponse httpResponse = send(getUrl(port, HttpRouter.DECOMMISSION), HttpServer.Method.PUT, body); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - assertEquals(body, httpResponse.responseBody); - httpServer.stopServer(); - } - - @Test - public void testArbitraryFileUpload() throws IOException { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServiceProvider httpServiceProvider = NullHttpServiceProvider.getInstance(); - httpServer.initialize(httpServiceProvider); - assertTrue(httpServer.startServer(0)); - int port = httpServer.getListeningPort(); - File tempFile = File.createTempFile("test-" + System.currentTimeMillis(), null); - Files.asCharSink(tempFile, StandardCharsets.UTF_8).write(TestVertxHttpServer.class.getName()); - String[] filenamesBeforeUploadRequest = listFiles(BodyHandler.DEFAULT_UPLOADS_DIRECTORY); - HttpResponse httpResponse = sendFile(getUrl(port, HttpRouter.BOOKIE_INFO), tempFile); - assertEquals(HttpServer.StatusCode.OK.getValue(), httpResponse.responseCode); - assertArrayEquals(filenamesBeforeUploadRequest, listFiles(BodyHandler.DEFAULT_UPLOADS_DIRECTORY)); - httpServer.stopServer(); - } - - private HttpResponse send(String url, HttpServer.Method method) throws IOException { - return send(url, method, ""); - } - - // HTTP request - private HttpResponse send(String url, HttpServer.Method method, String body) throws IOException { - URL obj = new URL(url); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - // optional, default is GET - con.setRequestMethod(method.toString()); - if (body != "") { - con.setDoOutput(true); - con.setFixedLengthStreamingMode(body.length()); - OutputStream outputStream = con.getOutputStream(); - outputStream.write(body.getBytes(StandardCharsets.UTF_8)); - outputStream.flush(); - } - int responseCode = con.getResponseCode(); - StringBuilder response = new StringBuilder(); - BufferedReader in = null; - try { - in = new BufferedReader(new InputStreamReader(con.getInputStream())); - String inputLine; - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - } finally { - if (in != null) { - in.close(); - } - } - return new HttpResponse(responseCode, response.toString()); - } - - private HttpResponse sendFile(String url, File file) throws IOException { - URL obj = new URL(url); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - String boundary = "---------------------------" + System.currentTimeMillis(); - // optional, default is GET - con.setRequestMethod("POST"); - con.setDoOutput(true); - con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); - try ( - OutputStream outputStream = con.getOutputStream(); - PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), - true); - FileInputStream fileInputStream = new FileInputStream(file); - ) { - writer.append("--" + boundary).append("\r\n"); - writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"file.txt\"").append("\r\n"); - writer.append("Content-Type: text/plain").append("\r\n"); - writer.append("\r\n"); - - byte[] buffer = new byte[4096]; - int bytesRead; - while ((bytesRead = fileInputStream.read(buffer)) != -1) { - outputStream.write(buffer, 0, bytesRead); - } - - writer.append("\r\n"); - writer.append("--" + boundary + "--").append("\r\n"); - } - int responseCode = con.getResponseCode(); - StringBuilder response = new StringBuilder(); - BufferedReader in = null; - try { - in = new BufferedReader(new InputStreamReader(con.getInputStream())); - String inputLine; - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - } finally { - if (in != null) { - in.close(); - } - } - return new HttpResponse(responseCode, response.toString()); - } - - private String[] listFiles(String directory) { - File directoryFile = new File(directory); - if (!directoryFile.exists() || !directoryFile.isDirectory()) { - return new String[0]; - } - return directoryFile.list(); - } - - private String getUrl(int port, String path) { - return "http://localhost:" + port + path; - } - - private class HttpResponse { - private int responseCode; - private String responseBody; - - public HttpResponse(int responseCode, String responseBody) { - this.responseCode = responseCode; - this.responseBody = responseBody; - } - } -} diff --git a/bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpsServer.java b/bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpsServer.java deleted file mode 100644 index 03f6651ee27..00000000000 --- a/bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpsServer.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.http.vertx; - -import java.io.FileInputStream; -import java.net.URL; -import java.security.KeyStore; -import java.security.SecureRandom; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManagerFactory; -import org.apache.bookkeeper.http.HttpServerConfiguration; -import org.apache.bookkeeper.http.HttpServiceProvider; -import org.apache.bookkeeper.http.NullHttpServiceProvider; -import org.junit.Test; - -/** - * Unit test {@link VertxHttpServer}. - */ -public class TestVertxHttpsServer { - - private static final String CLIENT_KEYSTORE_PATH = "./src/test/resources/vertx_client_key.jks"; - - private static final String CLIENT_TRUSTSTORE_PATH = "./src/test/resources/vertx_client_trust.jks"; - - private static final String CLIENT_WRONG_TRUSTSTORE_PATH = "./src/test/resources/vertx_client_wrong_trust.jks"; - - private static final String CLIENT_KEYSTORE_PASSWORD = "vertx_client_pwd"; - - private static final String CLIENT_TRUSTSTORE_PASSWORD = "vertx_client_pwd"; - - private static final String SERVER_KEYSTORE_PATH = "./src/test/resources/vertx_server_key.jks"; - - private static final String SERVER_TRUSTSTORE_PATH = "./src/test/resources/vertx_server_trust.jks"; - - private static final String SERVER_KEYSTORE_PASSWORD = "vertx_server_pwd"; - - private static final String SERVER_TRUSTSTORE_PASSWORD = "vertx_server_pwd"; - - @Test(timeout = 60_000) - public void testVertxServerTls() throws Exception { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServiceProvider httpServiceProvider = NullHttpServiceProvider.getInstance(); - httpServer.initialize(httpServiceProvider); - HttpServerConfiguration httpServerConfiguration = new HttpServerConfiguration(); - httpServerConfiguration.setTlsEnable(true); - httpServerConfiguration.setKeyStorePath(SERVER_KEYSTORE_PATH); - httpServerConfiguration.setKeyStorePassword(SERVER_KEYSTORE_PASSWORD); - httpServerConfiguration.setTrustStorePath(SERVER_TRUSTSTORE_PATH); - httpServerConfiguration.setTrustStorePassword(SERVER_TRUSTSTORE_PASSWORD); - httpServer.startServer(0, "localhost", httpServerConfiguration); - int actualPort = httpServer.getListeningPort(); - SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); - // key store - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - KeyStore keyStore = KeyStore.getInstance("JKS"); - try (FileInputStream inputStream = new FileInputStream(CLIENT_KEYSTORE_PATH)) { - keyStore.load(inputStream, CLIENT_KEYSTORE_PASSWORD.toCharArray()); - } - keyManagerFactory.init(keyStore, "vertx_client_pwd".toCharArray()); - KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); - // trust store - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - KeyStore trustStore = KeyStore.getInstance("JKS"); - try (FileInputStream inputStream = new FileInputStream(CLIENT_TRUSTSTORE_PATH)) { - trustStore.load(inputStream, CLIENT_TRUSTSTORE_PASSWORD.toCharArray()); - } - trustManagerFactory.init(trustStore); - sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom()); - URL url = new URL("https://localhost:" + actualPort); - HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); - urlConnection.setHostnameVerifier((s, sslSession) -> true); - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); - urlConnection.setSSLSocketFactory(socketFactory); - urlConnection.setRequestMethod("GET"); - urlConnection.getResponseCode(); - httpServer.stopServer(); - } - - @Test(timeout = 60_000, expected = SSLHandshakeException.class) - public void testVertxServerTlsFailByCertNotMatch() throws Exception { - VertxHttpServer httpServer = new VertxHttpServer(); - HttpServerConfiguration httpServerConfiguration = new HttpServerConfiguration(); - httpServerConfiguration.setTlsEnable(true); - httpServerConfiguration.setKeyStorePath(SERVER_KEYSTORE_PATH); - httpServerConfiguration.setKeyStorePassword(SERVER_KEYSTORE_PASSWORD); - httpServerConfiguration.setTrustStorePath(SERVER_TRUSTSTORE_PATH); - httpServerConfiguration.setTrustStorePassword(SERVER_TRUSTSTORE_PASSWORD); - httpServer.startServer(0, "localhost", httpServerConfiguration); - int actualPort = httpServer.getListeningPort(); - SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); - // key store - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - KeyStore keyStore = KeyStore.getInstance("JKS"); - try (FileInputStream inputStream = new FileInputStream(CLIENT_KEYSTORE_PATH)) { - keyStore.load(inputStream, CLIENT_KEYSTORE_PASSWORD.toCharArray()); - } - keyManagerFactory.init(keyStore, "vertx_client_pwd".toCharArray()); - KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); - // trust store - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - KeyStore trustStore = KeyStore.getInstance("JKS"); - try (FileInputStream inputStream = new FileInputStream(CLIENT_WRONG_TRUSTSTORE_PATH)) { - trustStore.load(inputStream, CLIENT_TRUSTSTORE_PASSWORD.toCharArray()); - } - trustManagerFactory.init(trustStore); - sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom()); - URL url = new URL("https://localhost:" + actualPort); - HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); - urlConnection.setHostnameVerifier((s, sslSession) -> true); - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); - urlConnection.setSSLSocketFactory(socketFactory); - urlConnection.setRequestMethod("GET"); - urlConnection.getResponseCode(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/auth/TestAuth.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/auth/TestAuth.java deleted file mode 100644 index 5b15471c8ee..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/auth/TestAuth.java +++ /dev/null @@ -1,848 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.BookieConnectionPeer; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.proto.ClientConnectionPeer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test authentication. - */ -@RunWith(Parameterized.class) -public class TestAuth extends BookKeeperClusterTestCase { - static final Logger LOG = LoggerFactory.getLogger(TestAuth.class); - public static final String TEST_AUTH_PROVIDER_PLUGIN_NAME = "TestAuthProviderPlugin"; - private static final byte[] PASSWD = "testPasswd".getBytes(); - private static final byte[] ENTRY = "TestEntry".getBytes(); - - private static final byte[] SUCCESS_RESPONSE = {1}; - private static final byte[] FAILURE_RESPONSE = {2}; - private static final byte[] PAYLOAD_MESSAGE = {3}; - - enum ProtocolVersion { - ProtocolV2, ProtocolV3 - } - - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { - { ProtocolVersion.ProtocolV2 }, - { ProtocolVersion.ProtocolV3 }, - }); - } - - private final ProtocolVersion protocolVersion; - - public TestAuth(ProtocolVersion protocolVersion) { - super(0); // start them later when auth providers are configured - this.protocolVersion = protocolVersion; - } - - protected ClientConfiguration newClientConfiguration() { - ClientConfiguration conf = super.newClientConfiguration(); - conf.setUseV2WireProtocol(protocolVersion == ProtocolVersion.ProtocolV2); - return conf; - } - - // we pass in ledgerId because the method may throw exceptions - private void connectAndWriteToBookie(ClientConfiguration conf, AtomicLong ledgerWritten) - throws Exception { - LOG.info("Connecting to bookie"); - try (BookKeeper bkc = new BookKeeper(conf, zkc); - LedgerHandle l = bkc.createLedger(1, 1, DigestType.CRC32, - PASSWD)) { - ledgerWritten.set(l.getId()); - l.addEntry(ENTRY); - } - } - - /** - * check if the entry exists. Restart the bookie to allow - * access - */ - private int entryCount(long ledgerId, ServerConfiguration bookieConf, - ClientConfiguration clientConf) throws Exception { - LOG.info("Counting entries in {}", ledgerId); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - restartBookies(c -> { - c.setBookieAuthProviderFactoryClass( - AlwaysSucceedBookieAuthProviderFactory.class.getName()); - return c; - }); - - int count = 0; - try (BookKeeper bkc = new BookKeeper(clientConf, zkc); - LedgerHandle lh = bkc.openLedger(ledgerId, DigestType.CRC32, - PASSWD)) { - if (lh.getLastAddConfirmed() < 0) { - return 0; - } - Enumeration e = lh.readEntries(0, lh.getLastAddConfirmed()); - while (e.hasMoreElements()) { - count++; - assertTrue("Should match what we wrote", - Arrays.equals(e.nextElement().getEntry(), ENTRY)); - } - } - return count; - } - - /** - * Test an connection will authorize with a single message - * to the server and a single response. - */ - @Test - public void testSingleMessageAuth() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - AlwaysSucceedBookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - connectAndWriteToBookie(clientConf, ledgerId); // should succeed - - assertFalse(ledgerId.get() == -1); - assertEquals("Should have entry", 1, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - @Test - public void testCloseMethodCalledOnAuthProvider() throws Exception { - LogCloseCallsBookieAuthProviderFactory.closeCountersOnFactory.set(0); - LogCloseCallsBookieAuthProviderFactory.closeCountersOnConnections.set(0); - LogCloseCallsBookieAuthProviderFactory.initCountersOnFactory.set(0); - LogCloseCallsBookieAuthProviderFactory.initCountersOnConnections.set(0); - LogCloseCallsClientAuthProviderFactory.initCountersOnFactory.set(0); - LogCloseCallsClientAuthProviderFactory.closeCountersOnFactory.set(0); - - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - LogCloseCallsBookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - LogCloseCallsClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - connectAndWriteToBookie(clientConf, ledgerId); // should succeed - - assertFalse(ledgerId.get() == -1); - assertEquals("Should have entry", 1, entryCount(ledgerId.get(), bookieConf, clientConf)); - - stopAllBookies(); - - assertEquals(LogCloseCallsBookieAuthProviderFactory.initCountersOnConnections.get(), - LogCloseCallsBookieAuthProviderFactory.closeCountersOnConnections.get()); - assertTrue(LogCloseCallsBookieAuthProviderFactory.initCountersOnConnections.get() > 0); - - assertEquals(1, LogCloseCallsBookieAuthProviderFactory.initCountersOnFactory.get()); - assertEquals(1, LogCloseCallsBookieAuthProviderFactory.closeCountersOnFactory.get()); - - assertEquals(LogCloseCallsClientAuthProviderFactory.initCountersOnConnections.get(), - LogCloseCallsClientAuthProviderFactory.closeCountersOnConnections.get()); - assertTrue(LogCloseCallsClientAuthProviderFactory.initCountersOnConnections.get() > 0); - - assertEquals(1, LogCloseCallsClientAuthProviderFactory.initCountersOnFactory.get()); - assertEquals(1, LogCloseCallsClientAuthProviderFactory.closeCountersOnFactory.get()); - - } - - /** - * Test that when the bookie provider sends a failure message - * the client will not be able to write. - */ - @Test - public void testSingleMessageAuthFailure() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - AlwaysFailBookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - try { - connectAndWriteToBookie(clientConf, ledgerId); // should fail - fail("Shouldn't get this far"); - } catch (BKException.BKUnauthorizedAccessException bke) { - // client shouldnt be able to find enough bookies to - // write - } - assertFalse(ledgerId.get() == -1); - assertEquals("Shouldn't have entry", 0, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - /** - * Test that authentication works when the providers - * exchange multiple messages. - */ - @Test - public void testMultiMessageAuth() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - SucceedAfter3BookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - AtomicLong ledgerId = new AtomicLong(-1); - startAndStoreBookie(bookieConf); - connectAndWriteToBookie(clientConf, ledgerId); // should succeed - - assertFalse(ledgerId.get() == -1); - assertEquals("Should have entry", 1, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - /** - * Test that when the bookie provider sends a failure message - * the client will not be able to write. - */ - @Test - public void testMultiMessageAuthFailure() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - FailAfter3BookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - try { - connectAndWriteToBookie(clientConf, ledgerId); // should fail - fail("Shouldn't get this far"); - } catch (BKException.BKUnauthorizedAccessException bke) { - // bookie should have sent a negative response before - // breaking the conneciton - } - assertFalse(ledgerId.get() == -1); - assertEquals("Shouldn't have entry", 0, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - /** - * Test that when the bookie and the client have a different - * plugin configured, no messages will get through. - */ - @Test - public void testDifferentPluginFailure() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - DifferentPluginBookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - AtomicLong ledgerId = new AtomicLong(-1); - try { - connectAndWriteToBookie(clientConf, ledgerId); // should fail - fail("Shouldn't get this far"); - } catch (BKException.BKUnauthorizedAccessException bke) { - // bookie should have sent a negative response before - // breaking the conneciton - assertEquals(ProtocolVersion.ProtocolV3, protocolVersion); - } catch (BKException.BKNotEnoughBookiesException nebe) { - // With V2 we don't get the authorization error, but rather just - // fail to write to bookies. - assertEquals(ProtocolVersion.ProtocolV2, protocolVersion); - } - assertFalse(ledgerId.get() == -1); - assertEquals("Shouldn't have entry", 0, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - /** - * Test that when the plugin class does exist, but - * doesn't implement the interface, we fail predictably. - */ - @Test - public void testExistantButNotValidPlugin() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - "java.lang.String"); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - "java.lang.String"); - try { - startAndStoreBookie(bookieConf); - fail("Shouldn't get this far"); - } catch (RuntimeException e) { - // received correct exception - assertTrue("Wrong exception thrown", - e.getMessage().contains("not " - + BookieAuthProvider.Factory.class.getName())); - } - - try { - BookKeeper bkc = new BookKeeper(clientConf, zkc); - fail("Shouldn't get this far"); - } catch (RuntimeException e) { - // received correct exception - assertTrue("Wrong exception thrown", - e.getMessage().contains("not " - + ClientAuthProvider.Factory.class.getName())); - } - } - - /** - * Test that when the plugin class does not exist, - * the bookie will not start and the client will - * break. - */ - @Test - public void testNonExistantPlugin() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - "NonExistantClassNameForTestingAuthPlugins"); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - "NonExistantClassNameForTestingAuthPlugins"); - try { - startAndStoreBookie(bookieConf); - fail("Shouldn't get this far"); - } catch (RuntimeException e) { - // received correct exception - assertEquals("Wrong exception thrown", - e.getCause().getClass(), ClassNotFoundException.class); - } - - try { - BookKeeper bkc = new BookKeeper(clientConf, zkc); - fail("Shouldn't get this far"); - } catch (RuntimeException e) { - // received correct exception - assertEquals("Wrong exception thrown", - e.getCause().getClass(), ClassNotFoundException.class); - } - } - - /** - * Test that when the plugin on the bookie crashes, the client doesn't - * hang also, but it cannot write in any case. - */ - @Test - public void testCrashDuringAuth() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - CrashAfter3BookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - try { - connectAndWriteToBookie(clientConf, ledgerId); - fail("Shouldn't get this far"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // bookie won't respond, request will timeout, and then - // we wont be able to find a replacement - } - assertFalse(ledgerId.get() == -1); - assertEquals("Shouldn't have entry", 0, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - /** - * Test that when a bookie simply stops replying during auth, the client doesn't - * hang also, but it cannot write in any case. - */ - @Test - public void testCrashType2DuringAuth() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - CrashType2After3BookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - crashType2bookieInstance = startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - try { - connectAndWriteToBookie(clientConf, ledgerId); - fail("Shouldn't get this far"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // bookie won't respond, request will timeout, and then - // we wont be able to find a replacement - } - assertFalse(ledgerId.get() == -1); - assertEquals("Shouldn't have entry", 0, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - /** - * Client will try to perform authentication but bookies are not configured. - */ - @Test - public void testClientWithAuthAndBookieWithDisabledAuth() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - assertNull(bookieConf.getBookieAuthProviderFactoryClass()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - connectAndWriteToBookie(clientConf, ledgerId); // should succeed - - assertFalse(ledgerId.get() == -1); - assertEquals("Should have entry", 1, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - /** - * The plugin will drop the connection from the bookie side. - */ - @Test - public void testDropConnectionFromBookieAuthPlugin() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - DropConnectionBookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SendUntilCompleteClientAuthProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - try { - connectAndWriteToBookie(clientConf, ledgerId); // should fail - fail(); - } catch (BKNotEnoughBookiesException error){ - } - } - - BookieServer startAndStoreBookie(ServerConfiguration conf) throws Exception { - return startAndAddBookie(conf).getServer(); - } - - /** - * Factory for a bookie that always succeeds. - */ - public static class AlwaysSucceedBookieAuthProviderFactory - implements BookieAuthProvider.Factory { - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - addr.setAuthorizedId(new BookKeeperPrincipal("test-principal")); - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(SUCCESS_RESPONSE)); - completeCb.operationComplete(BKException.Code.OK, null); - } - }; - } - } - - private static class LogCloseCallsBookieAuthProviderFactory implements BookieAuthProvider.Factory { - - private static AtomicInteger closeCountersOnFactory = new AtomicInteger(); - private static AtomicInteger closeCountersOnConnections = new AtomicInteger(); - private static AtomicInteger initCountersOnFactory = new AtomicInteger(); - private static AtomicInteger initCountersOnConnections = new AtomicInteger(); - - @Override - public void init(ServerConfiguration conf) throws IOException { - initCountersOnFactory.incrementAndGet(); - } - - @Override - public void close() { - closeCountersOnFactory.incrementAndGet(); - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer connection, - AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - { - completeCb.operationComplete(BKException.Code.OK, null); - initCountersOnConnections.incrementAndGet(); - } - - @Override - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - } - - @Override - public void close() { - closeCountersOnConnections.incrementAndGet(); - } - }; - } - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - } - - /** - * Factory for a bookie that drops connections. - */ - public static class DropConnectionBookieAuthProviderFactory - implements BookieAuthProvider.Factory { - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - addr.disconnect(); - } - }; - } - } - - /** - * Factory for a bookie that always fails. - */ - public static class AlwaysFailBookieAuthProviderFactory - implements BookieAuthProvider.Factory { - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - addr.setAuthorizedId(new BookKeeperPrincipal("test-principal")); - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(FAILURE_RESPONSE)); - completeCb.operationComplete( - BKException.Code.UnauthorizedAccessException, null); - } - }; - } - } - - private static class LogCloseCallsClientAuthProviderFactory implements ClientAuthProvider.Factory { - - private static AtomicInteger initCountersOnFactory = new AtomicInteger(); - private static AtomicInteger initCountersOnConnections = new AtomicInteger(); - private static AtomicInteger closeCountersOnFactory = new AtomicInteger(); - private static AtomicInteger closeCountersOnConnections = new AtomicInteger(); - - @Override - public void init(ClientConfiguration conf) throws IOException { - initCountersOnFactory.incrementAndGet(); - } - - @Override - public ClientAuthProvider newProvider(ClientConnectionPeer connection, - AuthCallbacks.GenericCallback completeCb) { - return new ClientAuthProvider() { - - @Override - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - } - - @Override - public void close() { - closeCountersOnConnections.incrementAndGet(); - } - - @Override - public void init(AuthCallbacks.GenericCallback cb) { - initCountersOnConnections.incrementAndGet(); - completeCb.operationComplete(BKException.Code.OK, null); - } - }; - } - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void close() { - closeCountersOnFactory.incrementAndGet(); - } - - } - - /** - * Factory for bookie that will send until complete. - */ - private static class SendUntilCompleteClientAuthProviderFactory - implements ClientAuthProvider.Factory { - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ClientConfiguration conf) { - } - - @Override - public ClientAuthProvider newProvider(ClientConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new ClientAuthProvider() { - public void init(AuthCallbacks.GenericCallback cb) { - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(PAYLOAD_MESSAGE)); - } - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - byte[] type = m.getData(); - if (Arrays.equals(type, SUCCESS_RESPONSE)) { - addr.setAuthorizedId(new BookKeeperPrincipal("test-client-principal")); - completeCb.operationComplete(BKException.Code.OK, null); - } else if (Arrays.equals(type, FAILURE_RESPONSE)) { - completeCb.operationComplete(BKException.Code.UnauthorizedAccessException, null); - } else { - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(PAYLOAD_MESSAGE)); - } - } - }; - } - } - - /** - * Factory for bookie that succeeds after three messages. - */ - public static class SucceedAfter3BookieAuthProviderFactory - implements BookieAuthProvider.Factory { - AtomicInteger numMessages = new AtomicInteger(0); - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - if (numMessages.incrementAndGet() == 3) { - addr.setAuthorizedId(new BookKeeperPrincipal("test-principal")); - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(SUCCESS_RESPONSE)); - completeCb.operationComplete(BKException.Code.OK, null); - } else { - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(PAYLOAD_MESSAGE)); - } - } - }; - } - } - - /** - * Factory for bookie that fails after three messages. - */ - public static class FailAfter3BookieAuthProviderFactory - implements BookieAuthProvider.Factory { - AtomicInteger numMessages = new AtomicInteger(0); - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - if (numMessages.incrementAndGet() == 3) { - addr.setAuthorizedId(new BookKeeperPrincipal("test-principal")); - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(FAILURE_RESPONSE)); - completeCb.operationComplete(BKException.Code.UnauthorizedAccessException, - null); - } else { - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(PAYLOAD_MESSAGE)); - } - } - }; - } - } - - /** - * Factory for crashing the bookie after 3 messages with an auth provider. - */ - public static class CrashAfter3BookieAuthProviderFactory - implements BookieAuthProvider.Factory { - AtomicInteger numMessages = new AtomicInteger(0); - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - if (numMessages.incrementAndGet() == 3) { - throw new RuntimeException("Do bad things to the bookie"); - } else { - addr.setAuthorizedId(new BookKeeperPrincipal("test-principal")); - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(PAYLOAD_MESSAGE)); - } - } - }; - } - } - - private static BookieServer crashType2bookieInstance = null; - /** - * Factory for a bookie with CrashType2 after three messages. - */ - public static class CrashType2After3BookieAuthProviderFactory - implements BookieAuthProvider.Factory { - AtomicInteger numMessages = new AtomicInteger(0); - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - if (numMessages.incrementAndGet() != 3) { - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(PAYLOAD_MESSAGE)); - return; - } - crashType2bookieInstance.suspendProcessing(); - } - }; - } - } - - /** - * Factory for a DifferentAuthProviderPlugin. - */ - public static class DifferentPluginBookieAuthProviderFactory - implements BookieAuthProvider.Factory { - @Override - public String getPluginName() { - return "DifferentAuthProviderPlugin"; - } - - @Override - public void init(ServerConfiguration conf) { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - cb.operationComplete(BKException.Code.OK, AuthToken.wrap(FAILURE_RESPONSE)); - completeCb.operationComplete(BKException.Code.OK, null); - } - }; - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/AdvertisedAddressTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/AdvertisedAddressTest.java deleted file mode 100644 index e5671280cb2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/AdvertisedAddressTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; - -import java.io.File; -import java.util.Collection; -import java.util.UUID; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.PortManager; -import org.junit.Test; - -/** - * Tests for when the setAdvertisedAddress is specified. - */ -public class AdvertisedAddressTest extends BookKeeperClusterTestCase { - final int bookiePort = PortManager.nextFreePort(); - - public AdvertisedAddressTest() { - super(0); - } - - private String newDirectory(boolean createCurDir) throws Exception { - File d = tmpDirs.createNew("cookie", "tmpdir"); - if (createCurDir) { - new File(d, "current").mkdirs(); - } - return d.getPath(); - } - - /** - * Test starting bookie with clean state. - */ - @Test - public void testSetAdvertisedAddress() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory(false)) - .setLedgerDirNames(new String[] { newDirectory(false) }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - conf.setAdvertisedAddress("10.0.0.1"); - assertEquals("10.0.0.1", conf.getAdvertisedAddress()); - - BookieSocketAddress bkAddress = new BookieSocketAddress("10.0.0.1", bookiePort); - assertEquals(bkAddress, BookieImpl.getBookieAddress(conf)); - assertEquals(bkAddress.toBookieId(), BookieImpl.getBookieId(conf)); - - Bookie b = new TestBookieImpl(conf); - b.start(); - - BookKeeperAdmin bka = new BookKeeperAdmin(baseClientConf); - Collection bookies = bka.getAvailableBookies(); - - assertEquals(1, bookies.size()); - BookieId address = bookies.iterator().next(); - assertEquals(bkAddress.toBookieId(), address); - - b.shutdown(); - bka.close(); - } - - /** - * When advertised address is specified, it should override the use. - */ - @Test - public void testBothUseHostnameAndAdvertisedAddress() throws Exception { - ServerConfiguration conf = new ServerConfiguration().setBookiePort(bookiePort); - - conf.setAdvertisedAddress("10.0.0.1"); - conf.setUseHostNameAsBookieID(true); - - assertEquals("10.0.0.1", conf.getAdvertisedAddress()); - - BookieSocketAddress bkAddress = new BookieSocketAddress("10.0.0.1", bookiePort); - assertEquals(bkAddress, BookieImpl.getBookieAddress(conf)); - assertEquals(bkAddress.toBookieId(), BookieImpl.getBookieId(conf)); - } - - /** - * Test starting bookie with a bookieId. - */ - @Test - public void testSetBookieId() throws Exception { - String uuid = UUID.randomUUID().toString(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory(false)) - .setLedgerDirNames(new String[] { newDirectory(false) }) - .setBookiePort(bookiePort) - .setBookieId(uuid) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - conf.setAdvertisedAddress("10.0.0.1"); - assertEquals("10.0.0.1", conf.getAdvertisedAddress()); - assertEquals(uuid, conf.getBookieId()); - - BookieSocketAddress bkAddress = new BookieSocketAddress("10.0.0.1", bookiePort); - assertEquals(bkAddress, BookieImpl.getBookieAddress(conf)); - assertEquals(uuid, BookieImpl.getBookieId(conf).getId()); - - Bookie b = new TestBookieImpl(conf); - b.start(); - - BookKeeperAdmin bka = new BookKeeperAdmin(baseClientConf); - Collection bookies = bka.getAvailableBookies(); - - assertEquals(1, bookies.size()); - BookieId address = bookies.iterator().next(); - assertEquals(BookieId.parse(uuid), address); - - b.shutdown(); - bka.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieAccessor.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieAccessor.java deleted file mode 100644 index d0c8ab6a81d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieAccessor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import java.io.IOException; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; - -/** - * Accessor class to avoid making Bookie internals public. - */ -public class BookieAccessor { - /** - * Force a bookie to flush its ledger storage. - */ - public static void forceFlush(BookieImpl b) throws IOException { - CheckpointSourceList source = new CheckpointSourceList(b.journals); - Checkpoint cp = source.newCheckpoint(); - b.ledgerStorage.flush(); - source.checkpointComplete(cp, true); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieDeferredSyncTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieDeferredSyncTest.java deleted file mode 100644 index dcac8f03d20..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieDeferredSyncTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; - -import java.util.EnumSet; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.LedgerEntry; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Test the bookie journal without sync, driven by client with - * {@link WriteFlag#DEFERRED_SYNC} write flag. - */ -public class BookieDeferredSyncTest extends BookKeeperClusterTestCase { - - public BookieDeferredSyncTest() { - super(1); - } - - @Test - public void testWriteAndRecovery() throws Exception { - // this WriteHandle will not be closed - WriteHandle lh = result(bkc.newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .withDigestType(DigestType.CRC32C) - .withPassword(new byte[0]) - .execute()); - - int n = 10; - - long ledgerId = lh.getId(); - - for (int i = 0; i < n; i++) { - lh.append(("entry-" + i).getBytes(UTF_8)); - } - - try (ReadHandle readLh = result(bkc.newOpenLedgerOp() - .withLedgerId(ledgerId) - .withRecovery(true) - .withPassword(new byte[0]) - .execute())) { - - try (LedgerEntries entries = readLh.read(0, n - 1)) { - for (int i = 0; i < n; i++) { - org.apache.bookkeeper.client.api.LedgerEntry entry = entries.getEntry(i); - assertEquals("entry-" + i, new String(entry.getEntryBytes())); - } - } - } - } - - @Test - public void testCloseNoForce() throws Exception { - testClose(true); - } - - @Test - public void testCloseWithForce() throws Exception { - testClose(false); - } - - private void testClose(boolean force) throws Exception { - final int n = 10; - long ledgerId; - try (WriteHandle lh = result(bkc.newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .withDigestType(DigestType.CRC32C) - .withPassword(new byte[0]) - .execute())) { - - ledgerId = lh.getId(); - for (int i = 0; i < n; i++) { - lh.append(("entry-" + i).getBytes(UTF_8)); - } if (force) { - // with force() LastAddConfirmed is updated - result(lh.force()); - // on close metadata will have LastAddConfirmed = n - 1 - assertEquals(n - 1, lh.getLastAddConfirmed()); - } else { - // on close metadata will have LastAddConfirmed = -1 - assertEquals(-1, lh.getLastAddConfirmed()); - } - } - - if (force) { - // the reader will be able to read - try (ReadHandle readLh = result(bkc.newOpenLedgerOp() - .withLedgerId(ledgerId) - .withRecovery(true) - .withPassword(new byte[0]) - .execute())) { - - try (LedgerEntries entries = readLh.read(0, n - 1)) { - for (int i = 0; i < n; i++) { - LedgerEntry entry = entries.getEntry(i); - assertEquals("entry-" + i, new String(entry.getEntryBytes())); - } - } - - try (LedgerEntries entries = readLh.readUnconfirmed(0, n - 1)) { - for (int i = 0; i < n; i++) { - LedgerEntry entry = entries.getEntry(i); - assertEquals("entry-" + i, new String(entry.getEntryBytes())); - } - } - } - } else { - // reader will see LastAddConfirmed = -1 - try (ReadHandle readLh = result(bkc.newOpenLedgerOp() - .withLedgerId(ledgerId) - .withRecovery(true) - .withPassword(new byte[0]) - .execute())) { - assertEquals(-1, readLh.getLastAddConfirmed()); - - // entry will be readable with readUnconfirmed - try (LedgerEntries entries = readLh.readUnconfirmed(0, n - 1)) { - for (int i = 0; i < n; i++) { - LedgerEntry entry = entries.getEntry(i); - assertEquals("entry-" + i, new String(entry.getEntryBytes())); - } - } - } - } - } - - @Test - public void testForceWithDeferredSyncWriteFlags() throws Exception { - testForce(EnumSet.of(WriteFlag.DEFERRED_SYNC)); - } - - @Test - public void testForceNoWriteFlag() throws Exception { - // force API will work even without DEFERRED_SYNC flag - testForce(WriteFlag.NONE); - } - - private void testForce(EnumSet writeFlags) throws Exception { - try (WriteHandle lh = result(bkc.newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .withWriteFlags(writeFlags) - .withDigestType(DigestType.CRC32C) - .withPassword(new byte[0]) - .execute())) { - int n = 10; - for (int i = 0; i < n; i++) { - lh.append(("entry-" + i).getBytes(UTF_8)); - } - result(lh.force()); - assertEquals(n - 1, lh.getLastAddConfirmed()); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieImplTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieImplTest.java deleted file mode 100644 index 4787ae8d36f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieImplTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; - -import com.google.protobuf.ByteString; -import com.google.protobuf.UnsafeByteOperations; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.ByteBufList; -import org.apache.bookkeeper.util.PortManager; -import org.awaitility.Awaitility; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class BookieImplTest extends BookKeeperClusterTestCase { - private static final Logger log = LoggerFactory.getLogger(BookieImplTest.class); - - private static final int bookiePort = PortManager.nextFreePort(); - - private static final int ADD = 0; - private static final int RECOVERY_ADD = 1; - - public BookieImplTest() { - super(0); - } - - @Test - public void testWriteLac() throws Exception { - final String metadataServiceUri = zkUtil.getMetadataServiceUri(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri); - - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - RegistrationManager rm = metadataDriver.createRegistrationManager(); - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver).withRegistrationManager(rm).build(); - BookieImpl b = new TestBookieImpl(resources); - b.start(); - - final BookieImpl spyBookie = spy(b); - - final long ledgerId = 10; - final long lac = 23; - - DigestManager digestManager = DigestManager.instantiate(ledgerId, "".getBytes(StandardCharsets.UTF_8), - BookKeeper.DigestType.toProtoDigestType(BookKeeper.DigestType.CRC32), UnpooledByteBufAllocator.DEFAULT, - baseClientConf.getUseV2WireProtocol()); - - final ByteBufList toSend = digestManager.computeDigestAndPackageForSendingLac(lac); - ByteString body = UnsafeByteOperations.unsafeWrap(toSend.array(), toSend.arrayOffset(), toSend.readableBytes()); - - final ByteBuf lacToAdd = Unpooled.wrappedBuffer(body.asReadOnlyByteBuffer()); - final byte[] masterKey = ByteString.copyFrom("masterKey".getBytes()).toByteArray(); - - final ByteBuf explicitLACEntry = b.createExplicitLACEntry(ledgerId, lacToAdd); - lacToAdd.resetReaderIndex(); - - doReturn(explicitLACEntry) - .when(spyBookie) - .createExplicitLACEntry(eq(ledgerId), eq(lacToAdd)); - - AtomicBoolean complete = new AtomicBoolean(false); - final BookkeeperInternalCallbacks.WriteCallback writeCallback = - new BookkeeperInternalCallbacks.WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - complete.set(true); - } - }; - - spyBookie.setExplicitLac(lacToAdd, writeCallback, null, masterKey); - - Awaitility.await().untilAsserted(() -> assertTrue(complete.get())); - - assertEquals(0, lacToAdd.refCnt()); - assertEquals(0, explicitLACEntry.refCnt()); - - b.shutdown(); - - } - - @Test - public void testAddEntry() throws Exception { - mockAddEntryReleased(ADD); - } - - @Test - public void testRecoveryAddEntry() throws Exception { - mockAddEntryReleased(RECOVERY_ADD); - } - - public void mockAddEntryReleased(int flag) throws Exception { - final String metadataServiceUri = zkUtil.getMetadataServiceUri(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri); - - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - RegistrationManager rm = metadataDriver.createRegistrationManager(); - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver).withRegistrationManager(rm).build(); - BookieImpl b = new TestBookieImpl(resources); - b.start(); - - final BookieImpl spyBookie = spy(b); - - final long ledgerId = 10; - - final byte[] masterKey = ByteString.copyFrom("masterKey".getBytes()).toByteArray(); - - final ByteBuf masterKeyEntry = b.createMasterKeyEntry(ledgerId, masterKey); - - doReturn(masterKeyEntry) - .when(spyBookie) - .createMasterKeyEntry(eq(ledgerId), eq(masterKey)); - - final ByteBuf entry = generateEntry(ledgerId, 0); - - AtomicBoolean complete = new AtomicBoolean(false); - final BookkeeperInternalCallbacks.WriteCallback writeCallback = - new BookkeeperInternalCallbacks.WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - complete.set(true); - } - }; - - switch (flag) { - case ADD: - spyBookie.addEntry(entry, false, writeCallback, null, masterKey); - break; - case RECOVERY_ADD: - spyBookie.recoveryAddEntry(entry, writeCallback, null, masterKey); - break; - default: - throw new IllegalArgumentException("Only support ADD and RECOVERY_ADD flag."); - } - - Awaitility.await().untilAsserted(() -> assertTrue(complete.get())); - - assertEquals(0, entry.refCnt()); - assertEquals(0, masterKeyEntry.refCnt()); - - b.shutdown(); - - } - - private ByteBuf generateEntry(long ledger, long entry) { - byte[] data = ("ledger-" + ledger + "-" + entry).getBytes(); - ByteBuf bb = Unpooled.buffer(8 + 8 + data.length); - bb.writeLong(ledger); - bb.writeLong(entry); - bb.writeBytes(data); - return bb; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieInitializationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieInitializationTest.java deleted file mode 100644 index 5188eb816bb..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieInitializationTest.java +++ /dev/null @@ -1,1773 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.bookie.BookieJournalTest.writeV5Journal; -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithRegistrationManager; -import static org.apache.bookkeeper.util.BookKeeperConstants.AVAILABLE_NODE; -import static org.apache.bookkeeper.util.BookKeeperConstants.BOOKIE_STATUS_FILENAME; -import static org.apache.bookkeeper.util.TestUtils.countNumOfFiles; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasProperty; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.spy; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.BindException; -import java.net.InetAddress; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import org.apache.bookkeeper.bookie.BookieException.DiskPartitionDuplicationException; -import org.apache.bookkeeper.bookie.BookieException.MetadataStoreException; -import org.apache.bookkeeper.bookie.Journal.LastLogMark; -import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.BookKeeperClientStats; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.component.ComponentStarter; -import org.apache.bookkeeper.common.component.Lifecycle; -import org.apache.bookkeeper.common.component.LifecycleComponent; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.BookieServiceInfo; -import org.apache.bookkeeper.discover.BookieServiceInfo.Endpoint; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.http.HttpRouter; -import org.apache.bookkeeper.http.HttpServerLoader; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.exceptions.MetadataException; -import org.apache.bookkeeper.meta.zk.ZKMetadataBookieDriver; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.proto.DataFormats.BookieServiceInfoFormat; -import org.apache.bookkeeper.replication.AutoRecoveryMain; -import org.apache.bookkeeper.replication.ReplicationStats; -import org.apache.bookkeeper.server.Main; -import org.apache.bookkeeper.server.conf.BookieConfiguration; -import org.apache.bookkeeper.server.service.AutoRecoveryService; -import org.apache.bookkeeper.server.service.BookieService; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.prometheus.PrometheusMetricsProvider; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.LoggerOutput; -import org.apache.bookkeeper.util.PortManager; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.data.Stat; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.event.LoggingEvent; - -/** - * Testing bookie initialization cases. - */ -public class BookieInitializationTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory - .getLogger(BookieInitializationTest.class); - - private static ObjectMapper om = new ObjectMapper(); - - @Rule - public final TestName runtime = new TestName(); - @Rule - public LoggerOutput loggerOutput = new LoggerOutput(); - - public BookieInitializationTest() { - super(0); - } - - @Override - public void setUp() throws Exception { - String ledgersPath = "/ledgers" + runtime.getMethodName(); - super.setUp(ledgersPath); - zkUtil.createBKEnsemble(ledgersPath); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testOneJournalReplayForBookieRestartInReadOnlyMode() throws Exception { - testJournalReplayForBookieRestartInReadOnlyMode(1); - } - - @Test - public void testMultipleJournalReplayForBookieRestartInReadOnlyMode() throws Exception { - testJournalReplayForBookieRestartInReadOnlyMode(4); - } - - /** - * Tests that journal replay works correctly when bookie crashes and starts up in RO mode. - */ - private void testJournalReplayForBookieRestartInReadOnlyMode(int numOfJournalDirs) throws Exception { - File tmpLedgerDir = tmpDirs.createNew("DiskCheck", "test"); - File tmpJournalDir = tmpDirs.createNew("DiskCheck", "test"); - - String[] journalDirs = new String[numOfJournalDirs]; - for (int i = 0; i < numOfJournalDirs; i++) { - journalDirs[i] = tmpJournalDir.getAbsolutePath() + "/journal-" + i; - } - - final ServerConfiguration conf = newServerConfiguration() - .setJournalDirsName(journalDirs) - .setLedgerDirNames(new String[] { tmpLedgerDir.getPath() }) - .setDiskCheckInterval(1000) - .setLedgerStorageClass(SortedLedgerStorage.class.getName()) - .setAutoRecoveryDaemonEnabled(false) - .setZkTimeout(5000); - - BookieServer server = new MockBookieServer(conf); - server.start(); - - List lastLogMarkList = new ArrayList<>(journalDirs.length); - - for (int i = 0; i < journalDirs.length; i++) { - Journal journal = ((BookieImpl) server.getBookie()).journals.get(i); - // LastLogMark should be (0, 0) at the bookie clean start - journal.getLastLogMark().readLog(); - lastLogMarkList.add(journal.getLastLogMark().markLog()); - assertEquals(0, lastLogMarkList.get(i).getCurMark().compare(new LogMark(0, 0))); - } - - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setMetadataServiceUri(metadataServiceUri); - BookKeeper bkClient = new BookKeeper(clientConf); - - // Create multiple ledgers for adding entries to multiple journals - for (int i = 0; i < journalDirs.length; i++) { - LedgerHandle lh = bkClient.createLedger(1, 1, 1, DigestType.CRC32, "passwd".getBytes()); - long entryId = -1; - // Ensure that we have non-zero number of entries - long numOfEntries = new Random().nextInt(10) + 3; - for (int j = 0; j < numOfEntries; j++) { - entryId = lh.addEntry("data".getBytes()); - } - assertEquals(entryId, (numOfEntries - 1)); - lh.close(); - } - - for (int i = 0; i < journalDirs.length; i++) { - Journal journal = ((BookieImpl) server.getBookie()).journals.get(i); - // In-memory LastLogMark should be updated with every write to journal - assertTrue(journal.getLastLogMark().getCurMark().compare(lastLogMarkList.get(i).getCurMark()) > 0); - lastLogMarkList.set(i, journal.getLastLogMark().markLog()); - } - - // Kill Bookie abruptly before entries are flushed to disk - server.shutdown(); - - conf.setDiskUsageThreshold(0.001f) - .setDiskUsageWarnThreshold(0.0f).setReadOnlyModeEnabled(true).setIsForceGCAllowWhenNoSpace(true) - .setMinUsableSizeForIndexFileCreation(5 * 1024); - server = new BookieServer( - conf, - TestBookieImpl.buildReadOnly(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - for (int i = 0; i < journalDirs.length; i++) { - Journal journal = ((BookieImpl) server.getBookie()).journals.get(i); - // LastLogMark should be (0, 0) before bookie restart since bookie crashed before persisting lastMark - assertEquals(0, journal.getLastLogMark().getCurMark().compare(new LogMark(0, 0))); - } - - int numOfRestarts = 3; - // Restart server multiple times to ensure that logs are never replayed and new files are not generated - for (int i = 0; i < numOfRestarts; i++) { - - int txnBefore = countNumOfFiles(conf.getJournalDirs(), "txn"); - int logBefore = countNumOfFiles(conf.getLedgerDirs(), "log"); - int idxBefore = countNumOfFiles(conf.getLedgerDirs(), "idx"); - - server.start(); - - for (int j = 0; j < journalDirs.length; j++) { - Journal journal = ((BookieImpl) server.getBookie()).journals.get(j); - assertTrue(journal.getLastLogMark().getCurMark().compare(lastLogMarkList.get(j).getCurMark()) > 0); - lastLogMarkList.set(j, journal.getLastLogMark().markLog()); - } - - server.shutdown(); - - // Every bookie restart initiates a new journal file - // Journals should not be replayed everytime since lastMark gets updated everytime - // New EntryLog files should not be generated. - assertEquals(journalDirs.length, (countNumOfFiles(conf.getJournalDirs(), "txn") - txnBefore)); - - // First restart should replay journal and generate new log/index files - // Subsequent runs should not generate new files (but can delete older ones) - if (i == 0) { - assertTrue((countNumOfFiles(conf.getLedgerDirs(), "log") - logBefore) > 0); - assertTrue((countNumOfFiles(conf.getLedgerDirs(), "idx") - idxBefore) > 0); - } else { - assertTrue((countNumOfFiles(conf.getLedgerDirs(), "log") - logBefore) <= 0); - assertTrue((countNumOfFiles(conf.getLedgerDirs(), "idx") - idxBefore) <= 0); - } - - server = new BookieServer( - conf, - TestBookieImpl.buildReadOnly(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - } - bkClient.close(); - } - - /** - * Verify the bookie server exit code. On ZooKeeper exception, should return - * exit code ZK_REG_FAIL = 4 - */ - @Test - public void testExitCodeZK_REG_FAIL() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setMetadataServiceUri(metadataServiceUri); - - - // simulating ZooKeeper exception by assigning a closed zk client to bk - MetadataBookieDriver metadataDriver = spy(BookieResources.createMetadataDriver(conf, NullStatsLogger.INSTANCE)); - RegistrationManager rm = spy(metadataDriver.createRegistrationManager()); - doThrow(new MetadataStoreException("mocked exception")) - .when(rm) - .registerBookie(any(BookieId.class), anyBoolean(), any(BookieServiceInfo.class)); - doReturn(rm) - .when(metadataDriver).createRegistrationManager(); - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver) - .withRegistrationManager(rm).build(); - BookieServer bkServer = new BookieServer(conf, new TestBookieImpl(resources), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - bkServer.start(); - bkServer.join(); - assertEquals("Failed to return ExitCode.ZK_REG_FAIL", - ExitCode.ZK_REG_FAIL, bkServer.getExitCode()); - } - - @Test - public void testBookieRegistrationWithSameZooKeeperClient() throws Exception { - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri) - .setListeningInterface(null); - - BookieId bookieId = BookieImpl.getBookieId(conf); - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - try (RegistrationManager rm = metadataDriver.createRegistrationManager(); - StateManager manager = new BookieStateManager(conf, rm)) { - manager.registerBookie(true).get(); - assertTrue( - "Bookie registration node doesn't exists!", - rm.isBookieRegistered(bookieId)); - - // test register bookie again if the registeration node is created by itself. - manager.registerBookie(true).get(); - assertTrue( - "Bookie registration node doesn't exists!", - rm.isBookieRegistered(bookieId)); - } - } - - /** - * Verify the bookie reg. Restarting bookie server will wait for the session - * timeout when previous reg node exists in zk. On zNode delete event, - * should continue startup - */ - @Test - public void testBookieRegistration() throws Exception { - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri) - .setListeningInterface(null); - - String bookieId = BookieImpl.getBookieAddress(conf).toString(); - final String bkRegPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf) - + "/" + AVAILABLE_NODE + "/" + bookieId; - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - metadataDriver.initialize(conf, NullStatsLogger.INSTANCE); - - try (RegistrationManager rm = metadataDriver.createRegistrationManager(); - StateManager manager = new BookieStateManager(conf, rm)) { - manager.registerBookie(true).get(); - } - Stat bkRegNode1 = zkc.exists(bkRegPath, false); - assertNotNull("Bookie registration has been failed", bkRegNode1); - - // simulating bookie restart, on restart bookie will create new - // zkclient and doing the registration. - try (MetadataBookieDriver newDriver = new ZKMetadataBookieDriver()) { - newDriver.initialize(conf, NullStatsLogger.INSTANCE); - - try (ZooKeeperClient newZk = createNewZKClient()) { - // deleting the znode, so that the bookie registration should - // continue successfully on NodeDeleted event - new Thread(() -> { - try { - Thread.sleep(conf.getZkTimeout() / 3); - zkc.delete(bkRegPath, -1); - } catch (Exception e) { - // Not handling, since the testRegisterBookie will fail - LOG.error("Failed to delete the znode :" + bkRegPath, e); - } - }).start(); - - try (RegistrationManager newRm = newDriver.createRegistrationManager(); - StateManager newMgr = new BookieStateManager(conf, newRm)) { - newMgr.registerBookie(true).get(); - } catch (IOException e) { - Throwable t = e.getCause(); - if (t instanceof KeeperException) { - KeeperException ke = (KeeperException) t; - assertTrue("ErrorCode:" + ke.code() - + ", Registration node exists", - ke.code() != KeeperException.Code.NODEEXISTS); - } - throw e; - } - - // verify ephemeral owner of the bkReg znode - Stat bkRegNode2 = newZk.exists(bkRegPath, false); - assertNotNull("Bookie registration has been failed", bkRegNode2); - assertTrue("Bookie is referring to old registration znode:" - + bkRegNode1 + ", New ZNode:" + bkRegNode2, bkRegNode1 - .getEphemeralOwner() != bkRegNode2.getEphemeralOwner()); - } - } - } - - @Test(timeout = 20000) - public void testBookieRegistrationWithFQDNHostNameAsBookieID() throws Exception { - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(metadataServiceUri) - .setUseHostNameAsBookieID(true) - .setListeningInterface(null); - - final BookieId bookieId = - BookieId.parse(InetAddress.getLocalHost().getCanonicalHostName() + ":" + conf.getBookiePort()); - - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - - try (RegistrationManager rm = metadataDriver.createRegistrationManager(); - StateManager manager = new BookieStateManager(conf, rm)) { - manager.registerBookie(true).get(); - assertTrue("Bookie registration node doesn't exists!", - rm.isBookieRegistered(bookieId)); - } - } - - @Test(timeout = 20000) - public void testBookieRegistrationWithShortHostNameAsBookieID() throws Exception { - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(metadataServiceUri) - .setUseHostNameAsBookieID(true) - .setUseShortHostName(true) - .setListeningInterface(null); - - final BookieId bookieId = BookieId.parse(InetAddress.getLocalHost().getCanonicalHostName().split("\\.", 2)[0] - + ":" + conf.getBookiePort()); - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - - try (RegistrationManager rm = metadataDriver.createRegistrationManager(); - StateManager manager = new BookieStateManager(conf, rm)) { - manager.registerBookie(true).get(); - assertTrue("Bookie registration node doesn't exists!", - rm.isBookieRegistered(bookieId)); - } - } - - /** - * Verify the bookie registration, it should throw - * KeeperException.NodeExistsException if the znode still exists even after - * the zk session timeout. - */ - @Test - public void testRegNodeExistsAfterSessionTimeOut() throws Exception { - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(metadataServiceUri) - .setListeningInterface(null); - - BookieId bookieId = BookieId.parse(InetAddress.getLocalHost().getHostAddress() + ":" - + conf.getBookiePort()); - String bkRegPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf) + "/" + AVAILABLE_NODE + "/" + bookieId; - - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - - try (RegistrationManager rm = metadataDriver.createRegistrationManager(); - StateManager manager = new BookieStateManager(conf, rm)) { - manager.registerBookie(true).get(); - assertTrue("Bookie registration node doesn't exists!", - rm.isBookieRegistered(bookieId)); - } - Stat bkRegNode1 = zkc.exists(bkRegPath, false); - assertNotNull("Bookie registration has been failed", - bkRegNode1); - - // simulating bookie restart, on restart bookie will create new - // zkclient and doing the registration. - try (MetadataBookieDriver newDriver = new ZKMetadataBookieDriver()) { - newDriver.initialize(conf, NullStatsLogger.INSTANCE); - - try (RegistrationManager newRm = newDriver.createRegistrationManager(); - StateManager newMgr = new BookieStateManager(conf, newRm)) { - newMgr.registerBookie(true).get(); - fail("Should throw NodeExistsException as the znode is not getting expired"); - } catch (ExecutionException ee) { - Throwable e = ee.getCause(); // IOException - Throwable t1 = e.getCause(); // BookieException.MetadataStoreException - Throwable t2 = t1.getCause(); // IOException - Throwable t3 = t2.getCause(); // KeeperException.NodeExistsException - - if (t3 instanceof KeeperException) { - KeeperException ke = (KeeperException) t3; - assertTrue("ErrorCode:" + ke.code() - + ", Registration node doesn't exists", - ke.code() == KeeperException.Code.NODEEXISTS); - - // verify ephemeral owner of the bkReg znode - Stat bkRegNode2 = zkc.exists(bkRegPath, false); - assertNotNull("Bookie registration has been failed", - bkRegNode2); - assertTrue( - "Bookie wrongly registered. Old registration znode:" - + bkRegNode1 + ", New znode:" + bkRegNode2, - bkRegNode1.getEphemeralOwner() == bkRegNode2 - .getEphemeralOwner()); - return; - } - throw ee; - } - } - } - - @Test(timeout = 20000) - public void testBookieRegistrationBookieServiceInfo() throws Exception { - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(metadataServiceUri) - .setUseHostNameAsBookieID(true) - .setUseShortHostName(true) - .setListeningInterface(null); - - final BookieId bookieId = BookieId.parse(InetAddress.getLocalHost().getCanonicalHostName().split("\\.", 2)[0] - + ":" + conf.getBookiePort()); - String bkRegPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf) + "/" + AVAILABLE_NODE + "/" + bookieId; - - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - - Endpoint endpoint = new Endpoint("test", 1281, "localhost", "bookie-rpc", - Collections.emptyList(), Collections.emptyList()); - BookieServiceInfo bsi = new BookieServiceInfo(Collections.emptyMap(), Arrays.asList(endpoint)); - Supplier supplier = () -> bsi; - - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager( - conf, conf.getLedgerDirs(), diskChecker); - try (RegistrationManager rm = metadataDriver.createRegistrationManager(); - StateManager manager = new BookieStateManager(conf, - NullStatsLogger.INSTANCE, - rm, ledgerDirsManager, supplier)) { - manager.registerBookie(true).get(); - assertTrue("Bookie registration node doesn't exists!", - rm.isBookieRegistered(bookieId)); - } - Stat bkRegNode = zkc.exists(bkRegPath, false); - assertNotNull("Bookie registration has been failed", bkRegNode); - - byte[] bkRegNodeData = zkc.getData(bkRegPath, null, null); - assertFalse("Bookie service info not written", bkRegNodeData == null || bkRegNodeData.length == 0); - - BookieServiceInfoFormat serializedBookieServiceInfo = BookieServiceInfoFormat.parseFrom(bkRegNodeData); - BookieServiceInfoFormat.Endpoint serializedEndpoint = serializedBookieServiceInfo.getEndpoints(0); - assertNotNull("Serialized Bookie endpoint not found", serializedEndpoint); - - assertEquals(endpoint.getId(), serializedEndpoint.getId()); - assertEquals(endpoint.getHost(), serializedEndpoint.getHost()); - assertEquals(endpoint.getPort(), serializedEndpoint.getPort()); - } - - /** - * Verify user cannot start if user is in permittedStartupUsers conf list BKException BKUnauthorizedAccessException - * if cannot start. - */ - @Test - public void testUserNotPermittedToStart() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - int port = PortManager.nextFreePort(); - conf.setMetadataServiceUri(null) - .setBookiePort(port) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }); - String userString = "larry, curly,moe,,"; - conf.setPermittedStartupUsers(userString); - BookieServer bs1 = null; - - boolean sawException = false; - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - fail("Bookkeeper should not have started since current user isn't in permittedStartupUsers"); - } catch (BookieException.BookieUnauthorizedAccessException buae) { - sawException = true; - } finally { - if (bs1 != null && bs1.isRunning()) { - bs1.shutdown(); - } - } - assertTrue("Should have thrown exception", sawException); - } - - /** - * Verify user cannot start if user is in permittedStartupUsers conf list BKException BKUnauthorizedAccessException - * if cannot start. - */ - @Test - public void testUserPermittedToStart() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - int port = PortManager.nextFreePort(); - conf.setMetadataServiceUri(null) - .setBookiePort(port) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }); - - BookieServer bs1 = null; - - // Multiple commas - String userString = "larry,,,curly ," + System.getProperty("user.name") + " ,moe"; - conf.setPermittedStartupUsers(userString); - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bs1.start(); - } catch (BookieException.BookieUnauthorizedAccessException buae) { - fail("Bookkeeper should have started since current user is in permittedStartupUsers"); - } finally { - if (bs1 != null && bs1.isRunning()) { - bs1.shutdown(); - } - } - - // Comma at end - userString = "larry ,curly, moe," + System.getProperty("user.name") + ","; - conf.setPermittedStartupUsers(userString); - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bs1.start(); - } catch (BookieException.BookieUnauthorizedAccessException buae) { - fail("Bookkeeper should have started since current user is in permittedStartupUsers"); - } finally { - if (bs1 != null && bs1.isRunning()) { - bs1.shutdown(); - } - } - } - - /** - * Verify user can start if user is not in permittedStartupUsers but it is empty BKException - * BKUnauthorizedAccessException if cannot start. - */ - @Test - public void testUserPermittedToStartWithMissingProperty() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - LOG.info("{}", conf); - - int port = PortManager.nextFreePort(); - conf.setMetadataServiceUri(null) - .setBookiePort(port) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }); - BookieServer bs1 = null; - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bs1.start(); - } catch (BookieException.BookieUnauthorizedAccessException buae) { - fail("Bookkeeper should have started since permittedStartupUser is not specified"); - } finally { - if (bs1 != null && bs1.isRunning()) { - bs1.shutdown(); - } - } - } - - /** - * Verify duplicate bookie server startup. Should throw - * java.net.BindException if already BK server is running - */ - @Test - public void testDuplicateBookieServerStartup() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - int port = PortManager.nextFreePort(); - conf.setBookiePort(port) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setMetadataServiceUri(metadataServiceUri); - BookieServer bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bs1.start(); - BookieServer bs2 = null; - // starting bk server with same conf - try { - bs2 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bs2.start(); - fail("Should throw BindException, as the bk server is already running!"); - } catch (BindException e) { - // Ok - } catch (IOException e) { - assertTrue("BKServer allowed duplicate Startups!", - e.getMessage().contains("bind")); - } finally { - bs1.shutdown(); - if (bs2 != null) { - bs2.shutdown(); - } - } - } - - @Test - public void testBookieServiceExceptionHandler() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "exception-handler"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - int port = PortManager.nextFreePort(); - conf.setBookiePort(port) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setMetadataServiceUri(metadataServiceUri); - - BookieConfiguration bkConf = new BookieConfiguration(conf); - BookieService service = new BookieService( - bkConf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, BookieResources.createAllocator(conf), - new MockUncleanShutdownDetection()); - CompletableFuture startFuture = ComponentStarter.startComponent(service); - - // shutdown the bookie service - service.getServer().getBookie().shutdown(); - - // the bookie service lifecycle component should be shutdown. - startFuture.get(); - } - - /** - * Mock InterleavedLedgerStorage class where addEntry is mocked to throw - * OutOfMemoryError. - */ - public static class MockInterleavedLedgerStorage extends InterleavedLedgerStorage { - AtomicInteger atmoicInt = new AtomicInteger(0); - - @Override - public long addEntry(ByteBuf entry) throws IOException { - if (atmoicInt.incrementAndGet() == 10) { - throw new OutOfMemoryError("Some Injected Exception"); - } - return super.addEntry(entry); - } - } - - @Test - public void testBookieStartException() throws Exception { - File journalDir = tmpDirs.createNew("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = tmpDirs.createNew("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - /* - * add few entries to journal file. - */ - int numOfEntries = 100; - writeV5Journal(BookieImpl.getCurrentDirectory(journalDir), numOfEntries, - "testV5Journal".getBytes()); - - /* - * This Bookie is configured to use MockInterleavedLedgerStorage. - * MockInterleavedLedgerStorage throws an Error for addEntry request. - * This is to simulate Bookie/BookieServer/BookieService 'start' failure - * because of 'Bookie.readJournal' failure. - */ - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - int port = PortManager.nextFreePort(); - conf.setBookiePort(port).setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }).setMetadataServiceUri(metadataServiceUri) - .setLedgerStorageClass(MockInterleavedLedgerStorage.class.getName()); - - BookieConfiguration bkConf = new BookieConfiguration(conf); - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - try (RegistrationManager rm = metadataDriver.createRegistrationManager()) { - /* - * create cookie and write it to JournalDir/LedgerDir. - */ - String instanceId = rm.getClusterInstanceId(); - Cookie.Builder cookieBuilder = Cookie.generateCookie(conf).setInstanceId(instanceId); - Cookie cookie = cookieBuilder.build(); - cookie.writeToDirectory(new File(journalDir, "current")); - cookie.writeToDirectory(new File(ledgerDir, "current")); - Versioned newCookie = new Versioned<>( - cookie.toString().getBytes(UTF_8), Version.NEW - ); - rm.writeCookie(BookieImpl.getBookieId(conf), newCookie); - } - - /* - * Create LifecycleComponent for BookieServer and start it. - */ - LifecycleComponent server = Main.buildBookieServer(bkConf); - CompletableFuture startFuture = ComponentStarter.startComponent(server); - - /* - * Since Bookie/BookieServer/BookieService is expected to fail, it would - * cause bookie-server component's exceptionHandler to get triggered. - * This exceptionHandler will make sure all of the components to get - * closed and then finally completes the Future. - */ - startFuture.get(); - - /* - * make sure that Component's exceptionHandler is called by checking if - * the error message of ExceptionHandler is logged. This Log message is - * defined in anonymous exceptionHandler class defined in - * ComponentStarter.startComponent method. - */ - loggerOutput.expect((List logEvents) -> { - assertThat(logEvents, - hasItem(hasProperty("message", containsString("Triggered exceptionHandler of Component:")))); - }); - } - - /** - * Test that if the journal reads an entry with negative length, it shuts down - * the bookie normally. An admin should look to see what has - * happened in this case. - */ - @Test - public void testNegativeLengthEntryBookieShutdown() throws Exception { - File journalDir = tmpDirs.createNew("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = tmpDirs.createNew("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writeV5Journal(BookieImpl.getCurrentDirectory(journalDir), 5, - "testV5Journal".getBytes(), true); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = null; - try { - b = new TestBookieImpl(conf); - b.start(); - assertFalse("Bookie should shutdown normally after catching IOException" - + " due to corrupt entry with negative length", b.isRunning()); - } finally { - if (b != null) { - b.shutdown(); - } - } - } - - @Test - public void testAutoRecoveryServiceExceptionHandler() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri); - - BookieConfiguration bkConf = new BookieConfiguration(conf); - AutoRecoveryService service = new AutoRecoveryService(bkConf, NullStatsLogger.INSTANCE); - CompletableFuture startFuture = ComponentStarter.startComponent(service); - - // shutdown the AutoRecovery service - service.getAutoRecoveryServer().shutdown(); - - // the AutoRecovery lifecycle component should be shutdown. - startFuture.get(); - } - - /** - * Verify bookie server starts up on ephemeral ports. - */ - @Test - public void testBookieServerStartupOnEphemeralPorts() throws Exception { - File tmpDir1 = tmpDirs.createNew("bookie", "test1"); - File tmpDir2 = tmpDirs.createNew("bookie", "test2"); - - ServerConfiguration conf1 = TestBKConfiguration.newServerConfiguration(); - conf1.setBookiePort(0) - .setJournalDirName(tmpDir1.getPath()) - .setLedgerDirNames( - new String[] { tmpDir1.getPath() }) - .setMetadataServiceUri(null); - assertEquals(0, conf1.getBookiePort()); - BookieServer bs1 = new BookieServer( - conf1, new TestBookieImpl(conf1), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bs1.start(); - assertFalse(0 == conf1.getBookiePort()); - - // starting bk server with same conf - ServerConfiguration conf2 = TestBKConfiguration.newServerConfiguration(); - conf2.setBookiePort(0) - .setJournalDirName(tmpDir2.getPath()) - .setLedgerDirNames( - new String[] { tmpDir2.getPath() }) - .setMetadataServiceUri(null); - BookieServer bs2 = new BookieServer( - conf2, new TestBookieImpl(conf2), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - bs2.start(); - assertFalse(0 == conf2.getBookiePort()); - - // these two bookies are listening on different ports eventually - assertFalse(conf1.getBookiePort() == conf2.getBookiePort()); - } - - /** - * Verify bookie start behaviour when ZK Server is not running. - */ - @Test - public void testStartBookieWithoutZKServer() throws Exception { - zkUtil.killCluster(); - - File tmpDir = tmpDirs.createNew("bookie", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()).setZkTimeout(5000); - - try { - new TestBookieImpl(conf); - fail("Should throw ConnectionLossException as ZKServer is not running!"); - } catch (BookieException.MetadataStoreException e) { - // expected behaviour - } - } - - /** - * Verify that if I try to start a bookie without zk initialized, it won't - * prevent me from starting the bookie when zk is initialized. - */ - @Test - public void testStartBookieWithoutZKInitialized() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - final String zkRoot = "/ledgers2"; - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri(zkRoot)) - .setZkTimeout(5000); - try { - new TestBookieImpl(conf); - fail("Should throw NoNodeException"); - } catch (Exception e) { - // shouldn't be able to start - } - ServerConfiguration adminConf = new ServerConfiguration(); - adminConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri(zkRoot)); - BookKeeperAdmin.format(adminConf, false, false); - - Bookie b = new TestBookieImpl(conf); - b.shutdown(); - } - - /** - * Check disk full. Expected to fail on start. - */ - @Test - public void testWithDiskFullReadOnlyDisabledOrForceGCAllowDisabled() throws Exception { - File tmpDir = tmpDirs.createNew("DiskCheck", "test"); - long usableSpace = tmpDir.getUsableSpace(); - long totalSpace = tmpDir.getTotalSpace(); - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setLedgerStorageClass(InterleavedLedgerStorage.class.getName()) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setDiskCheckInterval(1000) - .setDiskUsageThreshold((1.0f - ((float) usableSpace / (float) totalSpace)) * 0.999f) - .setDiskUsageWarnThreshold(0.0f) - .setMetadataServiceUri(metadataServiceUri) - .setZkTimeout(5000); - - // if isForceGCAllowWhenNoSpace or readOnlyModeEnabled is not set and Bookie is - // started when Disk is full, then it will fail to start with NoWritableLedgerDirException - - conf.setMinUsableSizeForEntryLogCreation(Long.MAX_VALUE) - .setReadOnlyModeEnabled(false); - try { - new TestBookieImpl(conf); - fail("NoWritableLedgerDirException expected"); - } catch (NoWritableLedgerDirException e) { - // expected - } - - conf.setMinUsableSizeForEntryLogCreation(Long.MIN_VALUE) - .setReadOnlyModeEnabled(false); - try { - new TestBookieImpl(conf); - fail("NoWritableLedgerDirException expected"); - } catch (NoWritableLedgerDirException e) { - // expected - } - - conf.setMinUsableSizeForEntryLogCreation(Long.MAX_VALUE) - .setReadOnlyModeEnabled(true); - Bookie bookie = null; - try { - // bookie is okay to start up when readonly mode is enabled because entry log file creation - // is deferred. - bookie = new TestBookieImpl(conf); - } catch (NoWritableLedgerDirException e) { - fail("NoWritableLedgerDirException unexpected"); - } finally { - if (null != bookie) { - bookie.shutdown(); - } - } - } - - /** - * Check disk full. Expected to start as read-only. - */ - @Test - public void testWithDiskFullReadOnlyEnabledAndForceGCAllowAllowed() throws Exception { - File tmpDir = tmpDirs.createNew("DiskCheck", "test"); - long usableSpace = tmpDir.getUsableSpace(); - long totalSpace = tmpDir.getTotalSpace(); - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setDiskCheckInterval(1000) - .setDiskUsageThreshold((1.0f - ((float) usableSpace / (float) totalSpace)) * 0.999f) - .setDiskUsageWarnThreshold(0.0f) - .setMetadataServiceUri(metadataServiceUri) - .setZkTimeout(5000); - - // if isForceGCAllowWhenNoSpace and readOnlyModeEnabled are set, then Bookie should - // start with readonlymode when Disk is full (assuming there is no need for creation of index file - // while replaying the journal) - conf.setReadOnlyModeEnabled(true) - .setIsForceGCAllowWhenNoSpace(true); - final Bookie bk = new TestBookieImpl(conf); - bk.start(); - Thread.sleep((conf.getDiskCheckInterval() * 2) + 100); - - assertTrue(bk.isReadOnly()); - bk.shutdown(); - } - - @Test - public void testStartUpRegisteredWithUncleanShutdownDetection() throws Exception { - MockUncleanShutdownDetection uncleanShutdownDetection = new MockUncleanShutdownDetection(); - final ServerConfiguration conf = newServerConfiguration(); - BookieServer server = new MockBookieServer(conf, uncleanShutdownDetection); - server.start(); - assertTrue(uncleanShutdownDetection.getStartRegistered()); - server.shutdown(); - } - - @Test - public void testShutdownRegisteredWithUncleanShutdownDetection() throws Exception { - MockUncleanShutdownDetection uncleanShutdownDetection = new MockUncleanShutdownDetection(); - final ServerConfiguration conf = newServerConfiguration(); - BookieServer server = new MockBookieServer(conf, uncleanShutdownDetection); - server.start(); - server.shutdown(); - assertTrue(uncleanShutdownDetection.getShutdownRegistered()); - } - - class MockBookieServer extends BookieServer { - ServerConfiguration conf; - - public MockBookieServer(ServerConfiguration conf) throws Exception { - super(conf, - new MockBookieWithNoopShutdown(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - this.conf = conf; - } - - public MockBookieServer(ServerConfiguration conf, - MockUncleanShutdownDetection uncleanShutdownDetection) throws Exception { - super(conf, - new MockBookieWithNoopShutdown(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - uncleanShutdownDetection); - this.conf = conf; - } - } - - class MockBookieWithNoopShutdown extends TestBookieImpl { - public MockBookieWithNoopShutdown(ServerConfiguration conf) throws Exception { - super(conf); - } - - // making Bookie Shutdown no-op. Ideally for this testcase we need to - // kill bookie abruptly to simulate the scenario where bookie is killed - // without execution of shutdownhook (and corresponding shutdown logic). - // Since there is no easy way to simulate abrupt kill of Bookie we are - // injecting noop Bookie Shutdown - @Override - synchronized int shutdown(int exitCode) { - return exitCode; - } - } - - @Test - public void testWithDiskFullAndAbilityToCreateNewIndexFile() throws Exception { - File tmpDir = tmpDirs.createNew("DiskCheck", "test"); - - final ServerConfiguration conf = newServerConfiguration() - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setDiskCheckInterval(1000) - .setLedgerStorageClass(SortedLedgerStorage.class.getName()) - .setAutoRecoveryDaemonEnabled(false) - .setZkTimeout(5000); - - BookieServer server = new MockBookieServer(conf); - server.start(); - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setMetadataServiceUri(metadataServiceUri); - BookKeeper bkClient = new BookKeeper(clientConf); - LedgerHandle lh = bkClient.createLedger(1, 1, 1, DigestType.CRC32, "passwd".getBytes()); - long entryId = -1; - long numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - entryId = lh.addEntry("data".getBytes()); - } - assertTrue("EntryId of the recently added entry should be 0", entryId == (numOfEntries - 1)); - // We want to simulate the scenario where Bookie is killed abruptly, so - // SortedLedgerStorage's EntryMemTable and IndexInMemoryPageManager are - // not flushed and hence when bookie is restarted it will replay the - // journal. Since there is no easy way to kill the Bookie abruptly, we - // are injecting no-op shutdown. - server.shutdown(); - - conf.setDiskUsageThreshold(0.001f) - .setDiskUsageWarnThreshold(0.0f).setReadOnlyModeEnabled(true).setIsForceGCAllowWhenNoSpace(true) - .setMinUsableSizeForIndexFileCreation(Long.MAX_VALUE); - server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - // Now we are trying to start the Bookie, which tries to replay the - // Journal. While replaying the Journal it tries to create the IndexFile - // for the ledger (whose entries are not flushed). but since we set - // minUsableSizeForIndexFileCreation to very high value, it wouldn't. be - // able to find any index dir when all discs are full - server.start(); - assertFalse("Bookie should be Shutdown", server.getBookie().isRunning()); - server.shutdown(); - - // Here we are setting MinUsableSizeForIndexFileCreation to very low - // value. So if index dirs are full then it will consider the dirs which - // have atleast MinUsableSizeForIndexFileCreation usable space for the - // creation of new Index file. - conf.setMinUsableSizeForIndexFileCreation(1 * 1024); - server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - server.start(); - Thread.sleep((conf.getDiskCheckInterval() * 2) + 1000); - assertTrue("Bookie should be up and running", server.getBookie().isRunning()); - assertTrue(server.getBookie().isReadOnly()); - server.shutdown(); - bkClient.close(); - } - - /** - * Check disk error for file. Expected to throw DiskErrorException. - */ - @Test - public void testWithDiskError() throws Exception { - File parent = tmpDirs.createNew("DiskCheck", "test"); - File child = File.createTempFile("DiskCheck", "test", parent); - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(child.getPath()) - .setLedgerDirNames(new String[] { child.getPath() }); - conf.setMetadataServiceUri(metadataServiceUri) - .setZkTimeout(5000); - try { - // LedgerDirsManager#init() is used in Bookie instantiation. - // Simulating disk errors by directly calling #init - LedgerDirsManager ldm = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - LedgerDirsMonitor ledgerMonitor = new LedgerDirsMonitor(conf, - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), - Collections.singletonList(ldm)); - ledgerMonitor.init(); - fail("should throw exception"); - } catch (Exception e) { - // expected - } - } - - /** - * if ALLOW_MULTIPLEDIRS_UNDER_SAME_DISKPARTITION is disabled then Bookie initialization - * will fail if there are multiple ledger/index/journal dirs are in same partition/filesystem. - */ - @Test - public void testAllowDiskPartitionDuplicationDisabled() throws Exception { - File tmpDir1 = tmpDirs.createNew("bookie", "test"); - File tmpDir2 = tmpDirs.createNew("bookie", "test"); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - int port = PortManager.nextFreePort(); - // multiple ledgerdirs in same diskpartition - conf.setMetadataServiceUri(metadataServiceUri) - .setZkTimeout(5000) - .setBookiePort(port) - .setJournalDirName(tmpDir1.getPath()) - .setLedgerDirNames(new String[] { tmpDir1.getPath(), tmpDir2.getPath() }) - .setIndexDirName(new String[] { tmpDir1.getPath() }) - .setAllowMultipleDirsUnderSameDiskPartition(false); - BookieServer bs1 = null; - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - fail("Bookkeeper should not have started since AllowMultipleDirsUnderSameDiskPartition is not enabled"); - } catch (DiskPartitionDuplicationException dpde) { - // Expected - } finally { - if (bs1 != null) { - bs1.shutdown(); - } - } - - tmpDir1 = tmpDirs.createNew("bookie", "test"); - tmpDir2 = tmpDirs.createNew("bookie", "test"); - port = PortManager.nextFreePort(); - // multiple indexdirs in same diskpartition - conf.setMetadataServiceUri(metadataServiceUri) - .setZkTimeout(5000) - .setBookiePort(port) - .setJournalDirName(tmpDir1.getPath()) - .setLedgerDirNames(new String[] { tmpDir1.getPath() }) - .setIndexDirName(new String[] { tmpDir1.getPath(), tmpDir2.getPath() }) - .setAllowMultipleDirsUnderSameDiskPartition(false); - bs1 = null; - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - fail("Bookkeeper should not have started since AllowMultipleDirsUnderSameDiskPartition is not enabled"); - } catch (DiskPartitionDuplicationException dpde) { - // Expected - } finally { - if (bs1 != null) { - bs1.shutdown(); - } - } - - tmpDir1 = tmpDirs.createNew("bookie", "test"); - tmpDir2 = tmpDirs.createNew("bookie", "test"); - port = PortManager.nextFreePort(); - // multiple journaldirs in same diskpartition - conf.setMetadataServiceUri(metadataServiceUri) - .setZkTimeout(5000) - .setBookiePort(port) - .setJournalDirsName(new String[] { tmpDir1.getPath(), tmpDir2.getPath() }) - .setLedgerDirNames(new String[] { tmpDir1.getPath() }) - .setIndexDirName(new String[] { tmpDir1.getPath()}) - .setAllowMultipleDirsUnderSameDiskPartition(false); - bs1 = null; - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - fail("Bookkeeper should not have started since AllowMultipleDirsUnderSameDiskPartition is not enabled"); - } catch (DiskPartitionDuplicationException dpde) { - // Expected - } finally { - if (bs1 != null) { - bs1.shutdown(); - } - } - } - - /** - * if ALLOW_MULTIPLEDIRS_UNDER_SAME_DISKPARTITION is enabled then Bookie initialization - * should succeed even if there are multiple ledger/index/journal dirs in the same diskpartition/filesystem. - */ - @Test - public void testAllowDiskPartitionDuplicationAllowed() throws Exception { - File tmpDir1 = tmpDirs.createNew("bookie", "test"); - File tmpDir2 = tmpDirs.createNew("bookie", "test"); - File tmpDir3 = tmpDirs.createNew("bookie", "test"); - File tmpDir4 = tmpDirs.createNew("bookie", "test"); - File tmpDir5 = tmpDirs.createNew("bookie", "test"); - File tmpDir6 = tmpDirs.createNew("bookie", "test"); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - int port = 12555; - conf.setMetadataServiceUri(metadataServiceUri) - .setZkTimeout(5000) - .setBookiePort(port) - .setJournalDirsName(new String[] { tmpDir1.getPath(), tmpDir2.getPath() }) - .setLedgerDirNames(new String[] { tmpDir3.getPath(), tmpDir4.getPath() }) - .setIndexDirName(new String[] { tmpDir5.getPath(), tmpDir6.getPath() }); - conf.setAllowMultipleDirsUnderSameDiskPartition(true); - BookieServer bs1 = null; - try { - bs1 = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - } catch (DiskPartitionDuplicationException dpde) { - fail("Bookkeeper should have started since AllowMultipleDirsUnderSameDiskPartition is enabled"); - } finally { - if (bs1 != null) { - bs1.shutdown(); - } - } - } - - private ZooKeeperClient createNewZKClient() throws Exception { - // create a zookeeper client - if (LOG.isDebugEnabled()) { - LOG.debug("Instantiate ZK Client"); - } - return ZooKeeperClient.newBuilder() - .connectString(zkUtil.getZooKeeperConnectString()) - .build(); - } - - /** - * Check bookie status should be able to persist on disk and retrieve when restart the bookie. - */ - @Test(timeout = 10000) - public void testPersistBookieStatus() throws Exception { - // enable persistent bookie status - File tmpDir = tmpDirs.createNew("bookie", "test"); - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setReadOnlyModeEnabled(true) - .setPersistBookieStatusEnabled(true) - .setMetadataServiceUri(metadataServiceUri); - BookieServer bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - Bookie bookie = bookieServer.getBookie(); - assertFalse(bookie.isReadOnly()); - // transition to readonly mode, bookie status should be persisted in ledger disks - bookie.getStateManager().transitionToReadOnlyMode().get(); - assertTrue(bookie.isReadOnly()); - - // restart bookie should start in read only mode - bookieServer.shutdown(); - bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - bookie = bookieServer.getBookie(); - assertTrue(bookie.isReadOnly()); - // transition to writable mode - bookie.getStateManager().transitionToWritableMode().get(); - // restart bookie should start in writable mode - bookieServer.shutdown(); - bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - bookie = bookieServer.getBookie(); - assertFalse(bookie.isReadOnly()); - bookieServer.shutdown(); - } - - /** - * Check when we start a ReadOnlyBookie, we should ignore bookie status. - */ - @Test(timeout = 10000) - public void testReadOnlyBookieShouldIgnoreBookieStatus() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setReadOnlyModeEnabled(true) - .setPersistBookieStatusEnabled(true) - .setMetadataServiceUri(metadataServiceUri); - // start new bookie - BookieServer bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - Bookie bookie = bookieServer.getBookie(); - // persist bookie status - bookie.getStateManager().transitionToReadOnlyMode().get(); - bookie.getStateManager().transitionToWritableMode().get(); - assertFalse(bookie.isReadOnly()); - bookieServer.shutdown(); - // start read only bookie - final ServerConfiguration readOnlyConf = TestBKConfiguration.newServerConfiguration(); - readOnlyConf.loadConf(conf); - readOnlyConf.setForceReadOnlyBookie(true); - - bookieServer = new BookieServer( - readOnlyConf, - TestBookieImpl.buildReadOnly(readOnlyConf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - - bookieServer.start(); - bookie = bookieServer.getBookie(); - assertTrue(bookie.isReadOnly()); - // transition to writable should fail - bookie.getStateManager().transitionToWritableMode().get(); - assertTrue(bookie.isReadOnly()); - bookieServer.shutdown(); - } - - /** - * Check that if there's multiple bookie status copies, as long as not all of them are corrupted, - * the bookie status should be retrievable. - */ - @Test(timeout = 10000) - public void testRetrieveBookieStatusWhenStatusFileIsCorrupted() throws Exception { - File[] tmpLedgerDirs = new File[3]; - String[] filePath = new String[tmpLedgerDirs.length]; - for (int i = 0; i < tmpLedgerDirs.length; i++) { - tmpLedgerDirs[i] = tmpDirs.createNew("bookie", "test" + i); - filePath[i] = tmpLedgerDirs[i].getPath(); - } - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(filePath[0]) - .setLedgerDirNames(filePath) - .setReadOnlyModeEnabled(true) - .setPersistBookieStatusEnabled(true) - .setMetadataServiceUri(metadataServiceUri); - // start a new bookie - BookieServer bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - // transition in to read only and persist the status on disk - Bookie bookie = (BookieImpl) bookieServer.getBookie(); - assertFalse(bookie.isReadOnly()); - bookie.getStateManager().transitionToReadOnlyMode().get(); - assertTrue(bookie.isReadOnly()); - // corrupt status file - List ledgerDirs = ((BookieImpl) bookie).getLedgerDirsManager().getAllLedgerDirs(); - corruptFile(new File(ledgerDirs.get(0), BOOKIE_STATUS_FILENAME)); - corruptFile(new File(ledgerDirs.get(1), BOOKIE_STATUS_FILENAME)); - // restart the bookie should be in read only mode - bookieServer.shutdown(); - bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - bookie = bookieServer.getBookie(); - assertTrue(bookie.isReadOnly()); - bookieServer.shutdown(); - } - - /** - * Check if the bookie would read the latest status if the status files are not consistent. - * @throws Exception - */ - @Test(timeout = 10000) - public void testReadLatestBookieStatus() throws Exception { - File[] tmpLedgerDirs = new File[3]; - String[] filePath = new String[tmpLedgerDirs.length]; - for (int i = 0; i < tmpLedgerDirs.length; i++) { - tmpLedgerDirs[i] = tmpDirs.createNew("bookie", "test" + i); - filePath[i] = tmpLedgerDirs[i].getPath(); - } - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(filePath[0]) - .setLedgerDirNames(filePath) - .setReadOnlyModeEnabled(true) - .setPersistBookieStatusEnabled(true) - .setMetadataServiceUri(metadataServiceUri); - // start a new bookie - BookieServer bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - // transition in to read only and persist the status on disk - Bookie bookie = (BookieImpl) bookieServer.getBookie(); - assertFalse(bookie.isReadOnly()); - bookie.getStateManager().transitionToReadOnlyMode().get(); - assertTrue(bookie.isReadOnly()); - // Manually update a status file, so it becomes the latest - Thread.sleep(1); - BookieStatus status = new BookieStatus(); - List dirs = new ArrayList(); - dirs.add(((BookieImpl) bookie).getLedgerDirsManager().getAllLedgerDirs().get(0)); - status.writeToDirectories(dirs); - // restart the bookie should start in writable state - bookieServer.shutdown(); - bookieServer = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bookieServer.start(); - bookie = bookieServer.getBookie(); - assertFalse(bookie.isReadOnly()); - bookieServer.shutdown(); - } - - private void corruptFile(File file) throws IOException { - FileOutputStream fos = new FileOutputStream(file); - BufferedWriter bw = null; - try { - bw = new BufferedWriter(new OutputStreamWriter(fos, UTF_8)); - byte[] bytes = new byte[64]; - new Random().nextBytes(bytes); - bw.write(new String(bytes)); - } finally { - if (bw != null) { - bw.close(); - } - fos.close(); - } - } - - @Test - public void testIOVertexHTTPServerEndpointForBookieWithPrometheusProvider() throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(tmpDir.getPath()).setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setBookiePort(PortManager.nextFreePort()).setMetadataServiceUri(metadataServiceUri) - .setListeningInterface(null); - - /* - * enable io.vertx http server - */ - int nextFreePort = PortManager.nextFreePort(); - conf.setStatsProviderClass(PrometheusMetricsProvider.class); - conf.setHttpServerEnabled(true); - conf.setProperty(HttpServerLoader.HTTP_SERVER_CLASS, "org.apache.bookkeeper.http.vertx.VertxHttpServer"); - conf.setHttpServerPort(nextFreePort); - - // 1. building the component stack: - LifecycleComponent server = Main.buildBookieServer(new BookieConfiguration(conf)); - // 2. start the server - CompletableFuture stackComponentFuture = ComponentStarter.startComponent(server); - while (server.lifecycleState() != Lifecycle.State.STARTED) { - Thread.sleep(100); - } - - // Now, hit the rest endpoint for metrics - URL url = new URL("http://localhost:" + nextFreePort + HttpRouter.METRICS); - URLConnection urlc = url.openConnection(); - BufferedReader in = new BufferedReader(new InputStreamReader(urlc.getInputStream())); - String inputLine; - StringBuilder metricsStringBuilder = new StringBuilder(); - while ((inputLine = in.readLine()) != null) { - metricsStringBuilder.append(inputLine); - } - in.close(); - String metrics = metricsStringBuilder.toString(); - // do primitive checks if metrics string contains some stats - assertTrue("Metrics should contain basic counters", metrics.contains(BookKeeperServerStats.BOOKIE_ADD_ENTRY)); - - // Now, hit the rest endpoint for configs - url = new URL("http://localhost:" + nextFreePort + HttpRouter.SERVER_CONFIG); - @SuppressWarnings("unchecked") - Map configMap = om.readValue(url, Map.class); - if (configMap.isEmpty() || !configMap.containsKey("bookiePort")) { - fail("Failed to map configurations to valid JSON entries."); - } - stackComponentFuture.cancel(true); - } - - @Test - public void testIOVertexHTTPServerEndpointForARWithPrometheusProvider() throws Exception { - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(metadataServiceUri).setListeningInterface(null); - - /* - * enable io.vertx http server - */ - int nextFreePort = PortManager.nextFreePort(); - conf.setStatsProviderClass(PrometheusMetricsProvider.class); - conf.setHttpServerEnabled(true); - conf.setProperty(HttpServerLoader.HTTP_SERVER_CLASS, "org.apache.bookkeeper.http.vertx.VertxHttpServer"); - conf.setHttpServerPort(nextFreePort); - - // 1. building the component stack: - LifecycleComponent server = AutoRecoveryMain.buildAutoRecoveryServer(new BookieConfiguration(conf)); - // 2. start the server - CompletableFuture stackComponentFuture = ComponentStarter.startComponent(server); - while (server.lifecycleState() != Lifecycle.State.STARTED) { - Thread.sleep(100); - } - - // Now, hit the rest endpoint for metrics - URL url = new URL("http://localhost:" + nextFreePort + HttpRouter.METRICS); - URLConnection urlc = url.openConnection(); - BufferedReader in = new BufferedReader(new InputStreamReader(urlc.getInputStream())); - String inputLine; - StringBuilder metricsStringBuilder = new StringBuilder(); - while ((inputLine = in.readLine()) != null) { - metricsStringBuilder.append(inputLine); - } - in.close(); - String metrics = metricsStringBuilder.toString(); - // do primitive checks if metrics string contains some stats - assertTrue("Metrics should contain basic counters", - metrics.contains(ReplicationStats.NUM_FULL_OR_PARTIAL_LEDGERS_REPLICATED)); - assertTrue("Metrics should contain basic counters from BookKeeper client", - metrics.contains(BookKeeperClientStats.CREATE_OP)); - - // Now, hit the rest endpoint for configs - url = new URL("http://localhost:" + nextFreePort + HttpRouter.SERVER_CONFIG); - @SuppressWarnings("unchecked") - Map configMap = om.readValue(url, Map.class); - if (configMap.isEmpty() || !configMap.containsKey("metadataServiceUri")) { - fail("Failed to map configurations to valid JSON entries."); - } - stackComponentFuture.cancel(true); - } - - /** - * Test that verifies if a bookie can't come up without its cookie in metadata store. - * @throws Exception - */ - @Test - public void testBookieConnectAfterCookieDelete() throws BookieException.UpgradeException { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - try { - runFunctionWithRegistrationManager(conf, rm -> { - try { - bookieConnectAfterCookieDeleteWorker(conf, rm); - } catch (Exception e) { - fail("Test failed to run: " + e.getMessage()); - } - return null; - }); - } catch (MetadataException | ExecutionException e) { - throw new BookieException.UpgradeException(e); - } - } - - private void bookieConnectAfterCookieDeleteWorker(ServerConfiguration conf, RegistrationManager rm) - throws Exception { - - File tmpLedgerDir = tmpDirs.createNew("BootupTest", "test"); - File tmpJournalDir = tmpDirs.createNew("BootupTest", "test"); - Integer numOfJournalDirs = 2; - - String[] journalDirs = new String[numOfJournalDirs]; - for (int i = 0; i < numOfJournalDirs; i++) { - journalDirs[i] = tmpJournalDir.getAbsolutePath() + "/journal-" + i; - } - - conf.setJournalDirsName(journalDirs); - conf.setLedgerDirNames(new String[] { tmpLedgerDir.getPath() }); - - LifecycleComponent server = Main.buildBookieServer(new BookieConfiguration(conf)); - server.start(); - - final BookieId bookieAddress = BookieImpl.getBookieId(conf); - - // Read cookie from registation manager - Versioned rmCookie = Cookie.readFromRegistrationManager(rm, bookieAddress); - - // Shutdown bookie - server.stop(); - - // Remove cookie from registration manager - rmCookie.getValue().deleteFromRegistrationManager(rm, conf, rmCookie.getVersion()); - - try { - Main.buildBookieServer(new BookieConfiguration(conf)); - fail("Bookie should not have been buildable. Cookie no present in metadata store."); - } catch (Exception e) { - LOG.info("As expected Bookie fails to be built without a cookie in metadata store."); - } - } - - @Test - public void testInvalidServiceMetadataURI() throws Exception { - testInvalidServiceMetadataURICase("zk+null:///ledgers"); // no hostname - testInvalidServiceMetadataURICase("zk+null://ledgers"); - testInvalidServiceMetadataURICase("zk+null:ledgers"); - { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri("//ledgers"); - try { - new BookieServer(conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - fail("Bookie metadata initialization must fail with metadata service uri: //ledgers"); - } catch (NullPointerException e) { - assertTrue(e.getMessage().contains("Invalid metadata service uri : //ledgers")); - } - } - - { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(""); - try { - new BookieServer(conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - fail("Bookie metadata initialization must fail with empty metadata service uri"); - } catch (NullPointerException e) { - assertTrue(e.getMessage().contains("Invalid metadata service uri :")); - } - } - } - - private void testInvalidServiceMetadataURICase(String uri) throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(uri); - try { - new BookieServer(conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - fail("Bookie metadata initialization must fail with an invalid metadata service uri: " + uri); - } catch (MetadataStoreException e) { - // ok - } - } - - @Test - public void testBookieIdSetting() throws Exception { - String customBookieId = "customId"; - // If BookieID is set, it takes precedence over network info. - final ServerConfiguration conf = newServerConfiguration().setBookieId(customBookieId); - BookieServer server = new MockBookieServer(conf); - server.start(); - assertEquals(customBookieId, server.getBookieId().toString()); - server.shutdown(); - } - - @Test - public void testBookieIdChange() throws Exception { - // By default, network info is set as Bookie Id and it is stored in the Cookie. - final ServerConfiguration conf = newServerConfiguration(); - LifecycleComponent server = Main.buildBookieServer(new BookieConfiguration(conf)); - server.start(); - server.stop(); - - // If BookieID is set, it takes precedence over network info. Because of that, the new Bookie start - // should fail with an InvalidCookieException, as now the custom BookieID takes precedence. - String customBookieId = "customId"; - conf.setBookieId(customBookieId); - try { - Main.buildBookieServer(new BookieConfiguration(conf)); - } catch (BookieException.InvalidCookieException e) { - // This is the expected case, as the customBookieId prevails over the default one. - } catch (Exception e) { - // Unexpected exception, failing. - fail(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalBypassTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalBypassTest.java deleted file mode 100644 index f1b8c2a3153..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalBypassTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; - -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Tests that we're skipping journal when it's configured to do so. - */ -@Slf4j -public class BookieJournalBypassTest extends BookKeeperClusterTestCase { - - private int bookieIdx = 0; - - public BookieJournalBypassTest() { - super(2); - } - - @Override - protected ServerTester startBookie(ServerConfiguration conf) throws Exception { - if (bookieIdx++ == 0) { - // First bookie will have the journal disabled - conf.setJournalWriteData(false); - } - return super.startBookie(conf); - } - - @Test - public void testJournalBypass() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - - BookieImpl bookieImpl = (BookieImpl) serverByIndex(0).getBookie(); - Journal journal0 = bookieImpl.journals.get(0); - LedgerStorage ls0 = serverByIndex(0).getBookie().getLedgerStorage(); - - bookieImpl = (BookieImpl) serverByIndex(1).getBookie(); - Journal journal1 = bookieImpl.journals.get(0); - LedgerStorage ls1 = serverByIndex(1).getBookie().getLedgerStorage(); - - ls0.flush(); - ls1.flush(); - - long bk0OffsetBefore = journal0.getLastLogMark().getCurMark().getLogFileOffset(); - long bk1OffsetBefore = journal1.getLastLogMark().getCurMark().getLogFileOffset(); - - writeEntries(conf); - ls0.flush(); - ls1.flush(); - - long bk0OffsetAfter = journal0.getLastLogMark().getCurMark().getLogFileOffset(); - long bk1OffsetAfter = journal1.getLastLogMark().getCurMark().getLogFileOffset(); - - int flushDelta = 10 * 1024; - int dataSize = 10 * 1024 * 1024; - - // Offset for journal-0 will be very close to previous point, just few KBs when flushing - assertEquals(bk0OffsetBefore, bk0OffsetAfter, flushDelta); - - // Offset for journal-0 should have changed with the data size - assertEquals(bk1OffsetBefore + dataSize, bk1OffsetAfter, flushDelta); - } - - private void writeEntries(ClientConfiguration conf) - throws Exception { - @Cleanup - BookKeeper bkc = new BookKeeper(conf); - - @Cleanup - WriteHandle wh = bkc.newCreateLedgerOp() - .withEnsembleSize(2) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .withPassword("".getBytes()) - .execute() - .join(); - - for (int i = 0; i < 10; i++) { - wh.append(new byte[1024 * 1024]); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalForceTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalForceTest.java deleted file mode 100644 index dee9502bda9..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalForceTest.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.Journal.ForceWriteRequest; -import org.apache.bookkeeper.bookie.Journal.LastLogMark; -import org.apache.bookkeeper.bookie.stats.JournalStats; -import org.apache.bookkeeper.common.collections.BatchedArrayBlockingQueue; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; - -/** - * Test the bookie journal. - */ -@RunWith(MockitoJUnitRunner.class) -@Slf4j -public class BookieJournalForceTest { - - private static final ByteBuf DATA = Unpooled.wrappedBuffer(new byte[]{}); - - @Rule - public TemporaryFolder tempDir = new TemporaryFolder(); - - @Test - public void testAckAfterSync() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(journalDir.getPath()) - .setMetadataServiceUri(null) - .setJournalAdaptiveGroupWrites(false); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = new Journal(0, journalDir, conf, ledgerDirsManager); - // machinery to suspend ForceWriteThread - CountDownLatch forceWriteThreadSuspendedLatch = new CountDownLatch(1); - BatchedArrayBlockingQueue supportQueue = - enableForceWriteThreadSuspension(forceWriteThreadSuspendedLatch, journal); - - journal = spy(journal); - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - journal.start(); - - LogMark lastLogMarkBeforeWrite = journal.getLastLogMark().markLog().getCurMark(); - CountDownLatch latch = new CountDownLatch(1); - long ledgerId = 1; - long entryId = 0; - journal.logAddEntry(ledgerId, entryId, DATA, false /* ackBeforeSync */, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - - // logAddEntry should not complete even if ForceWriteThread is suspended - // wait that an entry is written to the ForceWriteThread queue - while (supportQueue.isEmpty()) { - Thread.sleep(100); - } - assertEquals(1, latch.getCount()); - assertEquals(1, supportQueue.size()); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - // let ForceWriteThread work - forceWriteThreadSuspendedLatch.countDown(); - - // callback should complete now - assertTrue(latch.await(20, TimeUnit.SECONDS)); - - verify(jc, atLeast(1)).forceWrite(false); - - assertEquals(0, supportQueue.size()); - - // verify that log marker advanced - LastLogMark lastLogMarkAfterForceWrite = journal.getLastLogMark(); - assertTrue(lastLogMarkAfterForceWrite.getCurMark().compare(lastLogMarkBeforeWrite) > 0); - - journal.shutdown(); - } - - @Test - public void testAckBeforeSync() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setMetadataServiceUri(null) - .setJournalAdaptiveGroupWrites(false); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = new Journal(0, journalDir, conf, ledgerDirsManager); - // machinery to suspend ForceWriteThread - CountDownLatch forceWriteThreadSuspendedLatch = new CountDownLatch(1); - BatchedArrayBlockingQueue supportQueue = - enableForceWriteThreadSuspension(forceWriteThreadSuspendedLatch, journal); - - journal = spy(journal); - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - journal.start(); - - LogMark lastLogMarkBeforeWrite = journal.getLastLogMark().markLog().getCurMark(); - CountDownLatch latch = new CountDownLatch(1); - long ledgerId = 1; - long entryId = 0; - journal.logAddEntry(ledgerId, entryId, DATA, true /* ackBeforeSync */, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - // logAddEntry should complete even if ForceWriteThread is suspended - latch.await(20, TimeUnit.SECONDS); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - // we are never calling forceWrite - verify(jc, times(0)).forceWrite(false); - - // verify that log marker did not advance - LastLogMark lastLogMarkAfterForceWrite = journal.getLastLogMark(); - assertEquals(0, lastLogMarkAfterForceWrite.getCurMark().compare(lastLogMarkBeforeWrite)); - - // let the forceWriteThread exit - forceWriteThreadSuspendedLatch.countDown(); - - journal.shutdown(); - } - - @Test - public void testAckBeforeSyncWithJournalBufferedEntriesThreshold() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - final int journalBufferedEntriesThreshold = 10; - // sending a burst of entries, more than journalBufferedEntriesThreshold - final int numEntries = journalBufferedEntriesThreshold + 50; - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setJournalBufferedEntriesThreshold(journalBufferedEntriesThreshold) - .setMetadataServiceUri(null) - .setJournalAdaptiveGroupWrites(false); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = new Journal(0, journalDir, conf, ledgerDirsManager); - // machinery to suspend ForceWriteThread - CountDownLatch forceWriteThreadSuspendedLatch = new CountDownLatch(1); - enableForceWriteThreadSuspension(forceWriteThreadSuspendedLatch, journal); - - journal = spy(journal); - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - JournalStats journalStats = journal.getJournalStats(); - TestStatsProvider testStatsProvider = new TestStatsProvider(); - Counter flushMaxOutstandingBytesCounter = testStatsProvider.getStatsLogger("test") - .getCounter("flushMaxOutstandingBytesCounter"); - journalStats.setFlushMaxOutstandingBytesCounter(flushMaxOutstandingBytesCounter); - - journal.start(); - - LogMark lastLogMarkBeforeWrite = journal.getLastLogMark().markLog().getCurMark(); - CountDownLatch latch = new CountDownLatch(numEntries); - long ledgerId = 1; - for (long entryId = 0; entryId < numEntries; entryId++) { - journal.logAddEntry(ledgerId, entryId, DATA, true /* ackBeforeSync */, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - } - - // logAddEntry should complete even if ForceWriteThread is suspended - latch.await(20, TimeUnit.SECONDS); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - // anyway we are never calling forceWrite - verify(jc, times(0)).forceWrite(false); - - // verify that log marker did not advance - LastLogMark lastLogMarkAfterForceWrite = journal.getLastLogMark(); - assertEquals(0, lastLogMarkAfterForceWrite.getCurMark().compare(lastLogMarkBeforeWrite)); - - // let the forceWriteThread exit - forceWriteThreadSuspendedLatch.countDown(); - - assertTrue(flushMaxOutstandingBytesCounter.get() > 1); - journal.shutdown(); - } - - @Test - public void testInterleavedRequests() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setMetadataServiceUri(null); - - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = spy(new Journal(0, journalDir, conf, ledgerDirsManager)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - journal.start(); - - final int numEntries = 100; - CountDownLatch latchAckBeforeSynch = new CountDownLatch(numEntries); - CountDownLatch latchAckAfterSynch = new CountDownLatch(numEntries); - - long ledgerIdAckBeforeSync = 1; - long ledgerIdAckAfterSync = 2; - for (long entryId = 0; entryId < numEntries; entryId++) { - journal.logAddEntry(ledgerIdAckBeforeSync, entryId, DATA, true, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latchAckBeforeSynch.countDown(); - } - }, null); - journal.logAddEntry(ledgerIdAckAfterSync, entryId, DATA, false, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latchAckAfterSynch.countDown(); - } - }, null); - } - assertTrue(latchAckBeforeSynch.await(20, TimeUnit.SECONDS)); - assertTrue(latchAckAfterSynch.await(20, TimeUnit.SECONDS)); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - verify(jc, atLeast(1)).forceWrite(false); - - journal.shutdown(); - } - - @SuppressWarnings("unchecked") - private BatchedArrayBlockingQueue enableForceWriteThreadSuspension( - CountDownLatch forceWriteThreadSuspendedLatch, - Journal journal) throws InterruptedException { - BatchedArrayBlockingQueue supportQueue = new BatchedArrayBlockingQueue<>(10000); - BatchedArrayBlockingQueue forceWriteRequests = mock(BatchedArrayBlockingQueue.class); - doAnswer((Answer) (InvocationOnMock iom) -> { - supportQueue.put(iom.getArgument(0)); - return null; - }).when(forceWriteRequests).put(any(ForceWriteRequest.class)); - doAnswer((Answer) (InvocationOnMock iom) -> { - forceWriteThreadSuspendedLatch.await(); - ForceWriteRequest[] array = iom.getArgument(0); - return supportQueue.takeAll(array); - }).when(forceWriteRequests).takeAll(any()); - journal.setForceWriteRequests(forceWriteRequests); - return supportQueue; - } - - @Test - public void testForceLedger() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()); - conf.setJournalAdaptiveGroupWrites(false); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = new Journal(0, journalDir, conf, ledgerDirsManager); - // machinery to suspend ForceWriteThread - CountDownLatch forceWriteThreadSuspendedLatch = new CountDownLatch(1); - BatchedArrayBlockingQueue supportQueue = - enableForceWriteThreadSuspension(forceWriteThreadSuspendedLatch, journal); - - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - journal = spy(journal); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - journal.start(); - - LogMark lastLogMarkBeforeWrite = journal.getLastLogMark().markLog().getCurMark(); - CountDownLatch latch = new CountDownLatch(1); - long ledgerId = 1; - journal.forceLedger(ledgerId, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - - // forceLedger should not complete even if ForceWriteThread is suspended - // wait that an entry is written to the ForceWriteThread queue - while (supportQueue.isEmpty()) { - Thread.sleep(100); - } - assertEquals(1, latch.getCount()); - assertEquals(1, supportQueue.size()); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - // let ForceWriteThread work - forceWriteThreadSuspendedLatch.countDown(); - - // callback should complete now - assertTrue(latch.await(20, TimeUnit.SECONDS)); - - verify(jc, atLeast(1)).forceWrite(false); - - assertEquals(0, supportQueue.size()); - - // verify that log marker advanced - LastLogMark lastLogMarkAfterForceWrite = journal.getLastLogMark(); - assertTrue(lastLogMarkAfterForceWrite.getCurMark().compare(lastLogMarkBeforeWrite) > 0); - - journal.shutdown(); - } - - @Test - public void testFileChannelProvider() throws Exception { - File bookieFileDirectory = tempDir.newFile(); - ServerConfiguration config = TestBKConfiguration.newServerConfiguration(); - - DefaultFileChannel defaultFileChannel = spy(new DefaultFileChannel(bookieFileDirectory, config)); - - FileChannelProvider provider = spy(DefaultFileChannelProvider.class); - when(provider.open(bookieFileDirectory, config)).thenReturn(defaultFileChannel); - log.info("Journal Channel Provider: " + config.getJournalChannelProvider()); - // Open should return spied DefaultFileChannel here. - BookieFileChannel bookieFileChannel = provider.open(bookieFileDirectory, config); - bookieFileChannel.getFileChannel(); - verify(defaultFileChannel, times (1)).getFileChannel(); - bookieFileChannel.getFD(); - verify(defaultFileChannel, times (1)).getFD(); - bookieFileChannel.fileExists(bookieFileDirectory); - verify(defaultFileChannel, times (1)).fileExists(bookieFileDirectory); - provider.close(bookieFileChannel); - verify(defaultFileChannel, times (1)).close(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalMaxMemoryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalMaxMemoryTest.java deleted file mode 100644 index 9a288b6b8bf..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalMaxMemoryTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.util.concurrent.CountDownLatch; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.util.MemoryLimitController; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Test the bookie journal max memory controller. - */ -@RunWith(MockitoJUnitRunner.class) -@Slf4j -public class BookieJournalMaxMemoryTest { - - private static final ByteBuf DATA = Unpooled.wrappedBuffer(new byte[1024 * 1024]); - - @Rule - public TemporaryFolder tempDir = new TemporaryFolder(); - - @Test - public void testAckAfterSyncPageCacheFlush() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(journalDir.getPath()) - .setJournalMaxMemorySizeMb(1); - - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = spy(new Journal(0, journalDir, conf, ledgerDirsManager)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - MemoryLimitController mlc = spy(new MemoryLimitController(1)); - journal.setMemoryLimitController(mlc); - - journal.start(); - - CountDownLatch latch = new CountDownLatch(10); - - for (int i = 0; i < 10; i++) { - long ledgerId = 1; - long entryId = i; - - journal.logAddEntry(ledgerId, entryId, DATA, false, - (rc, ledgerId1, entryId1, addr, ctx) -> latch.countDown(), - null); - } - - latch.await(); - - verify(mlc, times(10)).reserveMemory(DATA.readableBytes()); - verify(mlc, times(10)).releaseMemory(DATA.readableBytes()); - - journal.shutdown(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalNoSyncTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalNoSyncTest.java deleted file mode 100644 index 6d444f02e22..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalNoSyncTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; - -import java.util.Enumeration; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Test the bookie journal without sync. - */ -public class BookieJournalNoSyncTest extends BookKeeperClusterTestCase { - - public BookieJournalNoSyncTest() { - super(1); - - baseConf.setJournalSyncData(false); - } - - @Test - public void testWriteToJournal() throws Exception { - LedgerHandle lh = bkc.createLedger(1, 1, DigestType.CRC32, new byte[0]); - - int n = 10; - - long ledgerId = lh.getId(); - - for (int i = 0; i < n; i++) { - lh.addEntry(("entry-" + i).getBytes()); - } - - restartBookies(); - - LedgerHandle readLh = bkc.openLedger(ledgerId, DigestType.CRC32, new byte[0]); - - Enumeration entries = readLh.readEntries(0, n - 1); - for (int i = 0; i < n; i++) { - LedgerEntry entry = entries.nextElement(); - assertEquals("entry-" + i, new String(entry.getEntry())); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalPageCacheFlushTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalPageCacheFlushTest.java deleted file mode 100644 index 3683e948e1a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalPageCacheFlushTest.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.Journal.ForceWriteRequest; -import org.apache.bookkeeper.bookie.Journal.LastLogMark; -import org.apache.bookkeeper.common.collections.BatchedArrayBlockingQueue; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; - -/** - * Test the bookie journal PageCache flush interval. - */ -@RunWith(MockitoJUnitRunner.class) -@Slf4j -public class BookieJournalPageCacheFlushTest { - - private static final ByteBuf DATA = Unpooled.wrappedBuffer(new byte[]{}); - - @Rule - public TemporaryFolder tempDir = new TemporaryFolder(); - - @SuppressWarnings("unchecked") - private BatchedArrayBlockingQueue enableForceWriteThreadSuspension( - CountDownLatch forceWriteThreadSuspendedLatch, - Journal journal) throws InterruptedException { - BatchedArrayBlockingQueue supportQueue = new BatchedArrayBlockingQueue<>(10000); - BatchedArrayBlockingQueue forceWriteRequests = mock(BatchedArrayBlockingQueue.class); - doAnswer((Answer) (InvocationOnMock iom) -> { - supportQueue.put(iom.getArgument(0)); - return null; - }).when(forceWriteRequests).put(any(ForceWriteRequest.class)); - doAnswer((Answer) (InvocationOnMock iom) -> { - forceWriteThreadSuspendedLatch.await(); - ForceWriteRequest[] array = iom.getArgument(0); - return supportQueue.takeAll(array); - }).when(forceWriteRequests).takeAll(any()); - journal.setForceWriteRequests(forceWriteRequests); - return supportQueue; - } - - @Test - public void testAckAfterSyncPageCacheFlush() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(journalDir.getPath()) - .setMetadataServiceUri(null) - .setJournalAdaptiveGroupWrites(false) - .setJournalSyncData(true) - .setJournalPageCacheFlushIntervalMSec(5000); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = new Journal(0, journalDir, conf, ledgerDirsManager); - CountDownLatch forceWriteThreadSuspendedLatch = new CountDownLatch(1); - BatchedArrayBlockingQueue supportQueue = - enableForceWriteThreadSuspension(forceWriteThreadSuspendedLatch, journal); - - journal = spy(journal); - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - journal.start(); - - LogMark lastLogMarkBeforeWrite = journal.getLastLogMark().markLog().getCurMark(); - CountDownLatch latch = new CountDownLatch(1); - long ledgerId = 1; - long entryId = 0; - long startTime = System.currentTimeMillis(); - journal.logAddEntry(ledgerId, entryId, DATA, false /* ackBeforeSync */, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - - while (supportQueue.isEmpty()) { - Thread.sleep(100); - } - - // forceWriteRequest insert into forceWriteRequestQueue not effected by journalPageCacheFlushInterval - assertTrue(System.currentTimeMillis() - startTime < 5000); - - assertEquals(1, latch.getCount()); - assertEquals(1, supportQueue.size()); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - // should not call forceWrite - verify(jc, times(0)).forceWrite(false); - - // let ForceWriteThread work - forceWriteThreadSuspendedLatch.countDown(); - // callback should complete now - assertTrue(latch.await(20, TimeUnit.SECONDS)); - - verify(jc, times(1)).forceWrite(false); - assertEquals(0, supportQueue.size()); - - // verify that log marker advanced - LastLogMark lastLogMarkAfterForceWrite = journal.getLastLogMark(); - assertTrue(lastLogMarkAfterForceWrite.getCurMark().compare(lastLogMarkBeforeWrite) > 0); - - journal.shutdown(); - } - - @Test - public void testAckBeforeSyncPageCacheFlush() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(journalDir.getPath()) - .setMetadataServiceUri(null) - .setJournalAdaptiveGroupWrites(false) - .setJournalSyncData(true) - .setJournalPageCacheFlushIntervalMSec(5000); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = new Journal(0, journalDir, conf, ledgerDirsManager); - - CountDownLatch forceWriteThreadSuspendedLatch = new CountDownLatch(1); - BatchedArrayBlockingQueue supportQueue = - enableForceWriteThreadSuspension(forceWriteThreadSuspendedLatch, journal); - - journal = spy(journal); - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - journal.start(); - - LogMark lastLogMarkBeforeWrite = journal.getLastLogMark().markLog().getCurMark(); - CountDownLatch latch = new CountDownLatch(1); - long ledgerId = 1; - long entryId = 0; - long startTime = System.currentTimeMillis(); - journal.logAddEntry(ledgerId, entryId, DATA, true /* ackBeforeSync */, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - - while (supportQueue.isEmpty()) { - Thread.sleep(100); - } - - // forceWriteRequest insert into forceWriteRequestQueue not effected by journalPageCacheFlushInterval - assertTrue(System.currentTimeMillis() - startTime < 5000); - assertEquals(1, supportQueue.size()); - - // callback should completed now - assertTrue(latch.await(20, TimeUnit.SECONDS)); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - // we are never calling foreWrite - verify(jc, times(0)).forceWrite(false); - - // verify that log marker did not advance - LastLogMark lastLogMarkAfterForceWrite = journal.getLastLogMark(); - assertEquals(0, lastLogMarkAfterForceWrite.getCurMark().compare(lastLogMarkBeforeWrite)); - - // let the forceWriteThread exit - forceWriteThreadSuspendedLatch.countDown(); - - journal.shutdown(); - } - - @Test - public void testAckBeforeUnSyncPageCacheFlush() throws Exception { - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(journalDir.getPath()) - .setMetadataServiceUri(null) - .setJournalAdaptiveGroupWrites(false) - .setJournalSyncData(false) - .setJournalPageCacheFlushIntervalMSec(5000); - - LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class); - Journal journal = new Journal(0, journalDir, conf, ledgerDirsManager); - - CountDownLatch forceWriteThreadSuspendedLatch = new CountDownLatch(1); - BatchedArrayBlockingQueue supportQueue = - enableForceWriteThreadSuspension(forceWriteThreadSuspendedLatch, journal); - - journal = spy(journal); - JournalChannel jc = spy(new JournalChannel(journalDir, 1)); - doReturn(jc).when(journal).newLogFile(anyLong(), nullable(Long.class)); - - journal.start(); - - CountDownLatch latch = new CountDownLatch(2); - long ledgerId = 1; - long entryId = 0; - LogMark lastLogMarkBeforeWrite = journal.getLastLogMark().markLog().getCurMark(); - journal.logAddEntry(ledgerId, entryId, DATA, true, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - - // the forceWriteRequest should not generated because of journalPageCacheFlushIntervalMSec control - assertEquals(0, supportQueue.size()); - - // wait journalPageCacheFlushIntervalMsec timeout - Thread.sleep(10000); - - // add an entry to journal, wake up journal main thread which is blocked on queue.take() - journal.logAddEntry(ledgerId, entryId + 1, DATA, true, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - latch.countDown(); - } - }, null); - - // wait forceWriteRequest generated - while (supportQueue.isEmpty()) { - Thread.sleep(100); - } - - // only one forceWriteRequest inserted into forceWriteRequestQueue - assertEquals(1, supportQueue.size()); - - // callback should completed now - assertTrue(latch.await(20, TimeUnit.SECONDS)); - - // in constructor of JournalChannel we are calling forceWrite(true) but it is not tracked by PowerMock - // because the 'spy' is applied only on return from the constructor - verify(jc, times(0)).forceWrite(true); - - // we are never calling foreWrite - verify(jc, times(0)).forceWrite(false); - - // verify that log marker did not advance - LastLogMark lastLogMarkAfterForceWrite = journal.getLastLogMark(); - assertEquals(0, lastLogMarkAfterForceWrite.getCurMark().compare(lastLogMarkBeforeWrite)); - - // let the forceWriteThread exit - forceWriteThreadSuspendedLatch.countDown(); - - journal.shutdown(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalTest.java deleted file mode 100644 index 21608a19b2b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalTest.java +++ /dev/null @@ -1,973 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCountUtil; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import lombok.Cleanup; -import org.apache.bookkeeper.bookie.Journal.LastLogMark; -import org.apache.bookkeeper.client.ClientUtil; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the bookie journal. - */ -@RunWith(MockitoJUnitRunner.class) -public class BookieJournalTest { - private static final Logger LOG = LoggerFactory.getLogger(BookieJournalTest.class); - - final Random r = new Random(System.currentTimeMillis()); - - final List tempDirs = new ArrayList(); - - File createTempDir(String prefix, String suffix) throws IOException { - File dir = IOUtils.createTempDir(prefix, suffix); - tempDirs.add(dir); - return dir; - } - - @After - public void tearDown() throws Exception { - for (File dir : tempDirs) { - FileUtils.deleteDirectory(dir); - } - tempDirs.clear(); - } - - private void writeIndexFileForLedger(File indexDir, long ledgerId, - byte[] masterKey) - throws Exception { - File fn = new File(indexDir, IndexPersistenceMgr.getLedgerName(ledgerId)); - fn.getParentFile().mkdirs(); - FileInfo fi = new FileInfo(fn, masterKey, FileInfo.CURRENT_HEADER_VERSION); - // force creation of index file - fi.write(new ByteBuffer[]{ ByteBuffer.allocate(0) }, 0); - fi.close(true); - } - - private void writePartialIndexFileForLedger(File indexDir, long ledgerId, - byte[] masterKey, boolean truncateToMasterKey) - throws Exception { - File fn = new File(indexDir, IndexPersistenceMgr.getLedgerName(ledgerId)); - fn.getParentFile().mkdirs(); - FileInfo fi = new FileInfo(fn, masterKey, FileInfo.CURRENT_HEADER_VERSION); - // force creation of index file - fi.write(new ByteBuffer[]{ ByteBuffer.allocate(0) }, 0); - fi.close(true); - // file info header - int headerLen = 8 + 4 + masterKey.length; - // truncate the index file - int leftSize; - if (truncateToMasterKey) { - leftSize = r.nextInt(headerLen); - } else { - leftSize = headerLen + r.nextInt(1024 - headerLen); - } - FileChannel fc = new RandomAccessFile(fn, "rw").getChannel(); - fc.truncate(leftSize); - fc.close(); - } - - /** - * Generate fence entry. - */ - private static ByteBuf generateFenceEntry(long ledgerId) { - ByteBuf bb = Unpooled.buffer(); - bb.writeLong(ledgerId); - bb.writeLong(BookieImpl.METAENTRY_ID_FENCE_KEY); - return bb; - } - - /** - * Generate meta entry with given master key. - */ - private static ByteBuf generateMetaEntry(long ledgerId, byte[] masterKey) { - ByteBuf bb = Unpooled.buffer(); - bb.writeLong(ledgerId); - bb.writeLong(BookieImpl.METAENTRY_ID_LEDGER_KEY); - bb.writeInt(masterKey.length); - bb.writeBytes(masterKey); - return bb; - } - - private void writeJunkJournal(File journalDir) throws Exception { - long logId = System.currentTimeMillis(); - File fn = new File(journalDir, Long.toHexString(logId) + ".txn"); - - FileChannel fc = new RandomAccessFile(fn, "rw").getChannel(); - - ByteBuffer zeros = ByteBuffer.allocate(512); - fc.write(zeros, 4 * 1024 * 1024); - fc.position(0); - - for (int i = 1; i <= 10; i++) { - fc.write(ByteBuffer.wrap("JunkJunkJunk".getBytes())); - } - } - - private void writePreV2Journal(File journalDir, int numEntries) throws Exception { - long logId = System.currentTimeMillis(); - File fn = new File(journalDir, Long.toHexString(logId) + ".txn"); - - FileChannel fc = new RandomAccessFile(fn, "rw").getChannel(); - - ByteBuffer zeros = ByteBuffer.allocate(512); - fc.write(zeros, 4 * 1024 * 1024); - fc.position(0); - - byte[] data = "JournalTestData".getBytes(); - long lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - for (int i = 1; i <= numEntries; i++) { - ByteBuf packet = ClientUtil.generatePacket(1, i, lastConfirmed, i * data.length, data); - lastConfirmed = i; - ByteBuffer lenBuff = ByteBuffer.allocate(4); - lenBuff.putInt(packet.readableBytes()); - lenBuff.flip(); - - fc.write(lenBuff); - fc.write(packet.nioBuffer()); - ReferenceCountUtil.release(packet); - } - } - - private static void moveToPosition(JournalChannel jc, long pos) throws IOException { - jc.fc.position(pos); - jc.bc.position = pos; - jc.bc.writeBufferStartPosition.set(pos); - } - - private static void updateJournalVersion(JournalChannel jc, int journalVersion) throws IOException { - long prevPos = jc.fc.position(); - try { - ByteBuffer versionBuffer = ByteBuffer.allocate(4); - versionBuffer.putInt(journalVersion); - versionBuffer.flip(); - jc.fc.position(4); - IOUtils.writeFully(jc.fc, versionBuffer); - jc.fc.force(true); - } finally { - jc.fc.position(prevPos); - } - } - - private JournalChannel writeV2Journal(File journalDir, int numEntries) throws Exception { - long logId = System.currentTimeMillis(); - JournalChannel jc = new JournalChannel(journalDir, logId); - - moveToPosition(jc, JournalChannel.VERSION_HEADER_SIZE); - - BufferedChannel bc = jc.getBufferedChannel(); - - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'X'); - long lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - for (int i = 1; i <= numEntries; i++) { - ByteBuf packet = ClientUtil.generatePacket(1, i, lastConfirmed, i * data.length, data); - lastConfirmed = i; - ByteBuffer lenBuff = ByteBuffer.allocate(4); - lenBuff.putInt(packet.readableBytes()); - lenBuff.flip(); - - bc.write(Unpooled.wrappedBuffer(lenBuff)); - bc.write(packet); - ReferenceCountUtil.release(packet); - } - bc.flushAndForceWrite(false); - - updateJournalVersion(jc, JournalChannel.V2); - - return jc; - } - - private JournalChannel writeV3Journal(File journalDir, int numEntries, byte[] masterKey) throws Exception { - long logId = System.currentTimeMillis(); - JournalChannel jc = new JournalChannel(journalDir, logId); - - moveToPosition(jc, JournalChannel.VERSION_HEADER_SIZE); - - BufferedChannel bc = jc.getBufferedChannel(); - - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'X'); - long lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - for (int i = 0; i <= numEntries; i++) { - ByteBuf packet; - if (i == 0) { - packet = generateMetaEntry(1, masterKey); - } else { - packet = ClientUtil.generatePacket(1, i, lastConfirmed, i * data.length, data); - } - lastConfirmed = i; - ByteBuffer lenBuff = ByteBuffer.allocate(4); - lenBuff.putInt(packet.readableBytes()); - lenBuff.flip(); - - bc.write(Unpooled.wrappedBuffer(lenBuff)); - bc.write(packet); - ReferenceCountUtil.release(packet); - } - bc.flushAndForceWrite(false); - - updateJournalVersion(jc, JournalChannel.V3); - - return jc; - } - - private JournalChannel writeV4Journal(File journalDir, int numEntries, byte[] masterKey) throws Exception { - long logId = System.currentTimeMillis(); - JournalChannel jc = new JournalChannel(journalDir, logId); - - moveToPosition(jc, JournalChannel.VERSION_HEADER_SIZE); - - BufferedChannel bc = jc.getBufferedChannel(); - - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'X'); - long lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - for (int i = 0; i <= numEntries; i++) { - ByteBuf packet; - if (i == 0) { - packet = generateMetaEntry(1, masterKey); - } else { - packet = ClientUtil.generatePacket(1, i, lastConfirmed, i * data.length, data); - } - lastConfirmed = i; - ByteBuffer lenBuff = ByteBuffer.allocate(4); - lenBuff.putInt(packet.readableBytes()); - lenBuff.flip(); - bc.write(Unpooled.wrappedBuffer(lenBuff)); - bc.write(packet); - ReferenceCountUtil.release(packet); - } - // write fence key - ByteBuf packet = generateFenceEntry(1); - ByteBuf lenBuf = Unpooled.buffer(); - lenBuf.writeInt(packet.readableBytes()); - bc.write(lenBuf); - bc.write(packet); - bc.flushAndForceWrite(false); - updateJournalVersion(jc, JournalChannel.V4); - return jc; - } - - private JournalChannel writeV4JournalWithInvalidRecord(File journalDir, - int numEntries, byte[] masterKey) throws Exception { - long logId = System.currentTimeMillis(); - JournalChannel jc = new JournalChannel(journalDir, logId); - - moveToPosition(jc, JournalChannel.VERSION_HEADER_SIZE); - - BufferedChannel bc = jc.getBufferedChannel(); - - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'X'); - long lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - for (int i = 0; i <= numEntries; i++) { - ByteBuf packet; - if (i == 0) { - packet = generateMetaEntry(1, masterKey); - } else { - packet = ClientUtil.generatePacket(1, i, lastConfirmed, i * data.length, data); - } - lastConfirmed = i; - ByteBuffer lenBuff = ByteBuffer.allocate(4); - if (i == numEntries - 1) { - //mock when flush data to file ,it writes an invalid entry to journal - lenBuff.putInt(-1); - } else { - lenBuff.putInt(packet.readableBytes()); - } - lenBuff.flip(); - bc.write(Unpooled.wrappedBuffer(lenBuff)); - bc.write(packet); - packet.release(); - } - - // write fence key - ByteBuf packet = generateFenceEntry(1); - ByteBuf lenBuf = Unpooled.buffer(); - lenBuf.writeInt(packet.readableBytes()); - //mock - bc.write(lenBuf); - bc.write(packet); - bc.flushAndForceWrite(false); - updateJournalVersion(jc, JournalChannel.V4); - - return jc; - } - - static JournalChannel writeV5Journal(File journalDir, int numEntries, - byte[] masterKey) throws Exception { - return writeV5Journal(journalDir, numEntries, masterKey, false); - } - - static JournalChannel writeV5Journal(File journalDir, int numEntries, - byte[] masterKey, boolean corruptLength) throws Exception { - long logId = System.currentTimeMillis(); - JournalChannel jc = new JournalChannel(journalDir, logId); - - BufferedChannel bc = jc.getBufferedChannel(); - - ByteBuf paddingBuff = Unpooled.buffer(); - paddingBuff.writeZero(2 * JournalChannel.SECTOR_SIZE); - byte[] data = new byte[4 * 1024 * 1024]; - Arrays.fill(data, (byte) 'X'); - long lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - long length = 0; - for (int i = 0; i <= numEntries; i++) { - ByteBuf packet; - if (i == 0) { - packet = generateMetaEntry(1, masterKey); - } else { - packet = ClientUtil.generatePacket(1, i, lastConfirmed, length, data, 0, i); - } - lastConfirmed = i; - length += i; - ByteBuf lenBuff = Unpooled.buffer(); - if (corruptLength) { - lenBuff.writeInt(-1); - } else { - lenBuff.writeInt(packet.readableBytes()); - } - bc.write(lenBuff); - bc.write(packet); - ReferenceCountUtil.release(packet); - Journal.writePaddingBytes(jc, paddingBuff, JournalChannel.SECTOR_SIZE); - } - // write fence key - ByteBuf packet = generateFenceEntry(1); - ByteBuf lenBuf = Unpooled.buffer(); - lenBuf.writeInt(packet.readableBytes()); - bc.write(lenBuf); - bc.write(packet); - Journal.writePaddingBytes(jc, paddingBuff, JournalChannel.SECTOR_SIZE); - bc.flushAndForceWrite(false); - updateJournalVersion(jc, JournalChannel.V5); - return jc; - } - - /** - * test that we can open a journal written without the magic - * word at the start. This is for versions of bookkeeper before - * the magic word was introduced - */ - @Test - public void testPreV2Journal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writePreV2Journal(BookieImpl.getCurrentDirectory(journalDir), 100); - writeIndexFileForLedger(BookieImpl.getCurrentDirectory(ledgerDir), 1, "testPasswd".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = createBookieAndReadJournal(conf); - - b.readEntry(1, 100); - try { - b.readEntry(1, 101); - fail("Shouldn't have found entry 101"); - } catch (Bookie.NoEntryException e) { - // correct behaviour - } - - b.shutdown(); - } - - @Test - public void testV4Journal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writeV4Journal(BookieImpl.getCurrentDirectory(journalDir), 100, "testPasswd".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - BookieImpl b = createBookieAndReadJournal(conf); - - b.readEntry(1, 100); - try { - b.readEntry(1, 101); - fail("Shouldn't have found entry 101"); - } catch (Bookie.NoEntryException e) { - // correct behaviour - } - assertTrue(b.handles.getHandle(1, "testPasswd".getBytes()).isFenced()); - - b.shutdown(); - } - - @Test - public void testV5Journal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writeV5Journal(BookieImpl.getCurrentDirectory(journalDir), 2 * JournalChannel.SECTOR_SIZE, - "testV5Journal".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - BookieImpl b = createBookieAndReadJournal(conf); - - for (int i = 1; i <= 2 * JournalChannel.SECTOR_SIZE; i++) { - b.readEntry(1, i); - } - try { - b.readEntry(1, 2 * JournalChannel.SECTOR_SIZE + 1); - fail("Shouldn't have found entry " + (2 * JournalChannel.SECTOR_SIZE + 1)); - } catch (Bookie.NoEntryException e) { - // correct behavior - } - assertTrue(b.handles.getHandle(1, "testV5Journal".getBytes()).isFenced()); - - b.shutdown(); - } - - /** - * Test that if the journal is all journal, we can not - * start the bookie. An admin should look to see what has - * happened in this case - */ - @Test - public void testAllJunkJournal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writeJunkJournal(BookieImpl.getCurrentDirectory(journalDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = null; - try { - b = new TestBookieImpl(conf); - fail("Shouldn't have been able to start without admin"); - } catch (Throwable t) { - // correct behaviour - } finally { - if (b != null) { - b.shutdown(); - } - } - } - - /** - * Test that we can start with an empty journal. - * This can happen if the bookie crashes between creating the - * journal and writing the magic word. It could also happen before - * the magic word existed, if the bookie started but nothing was - * ever written. - */ - @Test - public void testEmptyJournal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writePreV2Journal(BookieImpl.getCurrentDirectory(journalDir), 0); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = new TestBookieImpl(conf); - } - - /** - * Test that a journal can load if only the magic word and - * version are there. - */ - @Test - public void testHeaderOnlyJournal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writeV2Journal(BookieImpl.getCurrentDirectory(journalDir), 0); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = new TestBookieImpl(conf); - } - - /** - * Test that if a journal has junk at the end, it does not load. - * If the journal is corrupt like this, admin intervention is needed - */ - @Test - public void testJunkEndedJournal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - JournalChannel jc = writeV2Journal(BookieImpl.getCurrentDirectory(journalDir), 0); - jc.getBufferedChannel().write(Unpooled.wrappedBuffer("JunkJunkJunk".getBytes())); - jc.getBufferedChannel().flushAndForceWrite(false); - jc.close(); - - writeIndexFileForLedger(ledgerDir, 1, "testPasswd".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = null; - try { - b = new TestBookieImpl(conf); - } catch (Throwable t) { - // correct behaviour - } - } - - /** - * Test that if the bookie crashes while writing the length - * of an entry, that we can recover. - * - *

This is currently not the case, which is bad as recovery - * should be fine here. The bookie has crashed while writing - * but so the client has not be notified of success. - */ - @Test - public void testTruncatedInLenJournal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - JournalChannel jc = writeV2Journal( - BookieImpl.getCurrentDirectory(journalDir), 100); - ByteBuffer zeros = ByteBuffer.allocate(2048); - - jc.fc.position(jc.getBufferedChannel().position() - 0x429); - jc.fc.write(zeros); - jc.fc.force(false); - - writeIndexFileForLedger(BookieImpl.getCurrentDirectory(ledgerDir), - 1, "testPasswd".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = createBookieAndReadJournal(conf); - - b.readEntry(1, 99); - - try { - b.readEntry(1, 100); - fail("Shouldn't have found entry 100"); - } catch (Bookie.NoEntryException e) { - // correct behaviour - } - } - - /** - * Test that if the bookie crashes in the middle of writing - * the actual entry it can recover. - * In this case the entry will be available, but it will corrupt. - * This is ok, as the client will disregard the entry after looking - * at its checksum. - */ - @Test - public void testTruncatedInEntryJournal() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - JournalChannel jc = writeV2Journal( - BookieImpl.getCurrentDirectory(journalDir), 100); - ByteBuffer zeros = ByteBuffer.allocate(2048); - - jc.fc.position(jc.getBufferedChannel().position() - 0x300); - jc.fc.write(zeros); - jc.fc.force(false); - - writeIndexFileForLedger(BookieImpl.getCurrentDirectory(ledgerDir), - 1, "testPasswd".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Bookie b = createBookieAndReadJournal(conf); - - b.readEntry(1, 99); - - // still able to read last entry, but it's junk - ByteBuf buf = b.readEntry(1, 100); - assertEquals("Ledger Id is wrong", buf.readLong(), 1); - assertEquals("Entry Id is wrong", buf.readLong(), 100); - assertEquals("Last confirmed is wrong", buf.readLong(), 99); - assertEquals("Length is wrong", buf.readLong(), 100 * 1024); - buf.readLong(); // skip checksum - boolean allX = true; - for (int i = 0; i < 1024; i++) { - byte x = buf.readByte(); - allX = allX && x == (byte) 'X'; - } - assertFalse("Some of buffer should have been zeroed", allX); - - try { - b.readEntry(1, 101); - fail("Shouldn't have found entry 101"); - } catch (Bookie.NoEntryException e) { - // correct behaviour - } - } - - private BookieImpl createBookieAndReadJournal(ServerConfiguration conf) throws Exception { - BookieImpl b = new TestBookieImpl(conf); - for (Journal journal : b.journals) { - LastLogMark lastLogMark = journal.getLastLogMark().markLog(); - b.readJournal(); - assertTrue(journal.getLastLogMark().getCurMark().compare(lastLogMark.getCurMark()) > 0); - } - return b; - } - - /** - * Test journal replay with SortedLedgerStorage and a very small max - * arena size. - */ - @Test - public void testSortedLedgerStorageReplayWithSmallMaxArenaSize() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - JournalChannel jc = writeV2Journal( - BookieImpl.getCurrentDirectory(journalDir), 100); - - jc.fc.force(false); - - writeIndexFileForLedger(BookieImpl.getCurrentDirectory(ledgerDir), - 1, "testPasswd".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerStorageClass("org.apache.bookkeeper.bookie.SortedLedgerStorage"); - conf.setSkipListArenaMaxAllocSize(0); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }); - - BookieImpl b = new TestBookieImpl(conf); - b.readJournal(); - b.ledgerStorage.flush(); - b.readEntry(1, 80); - b.readEntry(1, 99); - } - - /** - * Test partial index (truncate master key) with pre-v3 journals. - */ - @Test - public void testPartialFileInfoPreV3Journal1() throws Exception { - testPartialFileInfoPreV3Journal(true); - } - - /** - * Test partial index with pre-v3 journals. - */ - @Test - public void testPartialFileInfoPreV3Journal2() throws Exception { - testPartialFileInfoPreV3Journal(false); - } - - /** - * Test partial index file with pre-v3 journals. - */ - private void testPartialFileInfoPreV3Journal(boolean truncateMasterKey) - throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writePreV2Journal(BookieImpl.getCurrentDirectory(journalDir), 100); - writePartialIndexFileForLedger(BookieImpl.getCurrentDirectory(ledgerDir), - 1, "testPasswd".getBytes(), truncateMasterKey); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - if (truncateMasterKey) { - try { - BookieImpl b = new TestBookieImpl(conf); - b.readJournal(); - fail("Should not reach here!"); - } catch (IOException ie) { - } - } else { - BookieImpl b = new TestBookieImpl(conf); - b.readJournal(); - b.readEntry(1, 100); - try { - b.readEntry(1, 101); - fail("Shouldn't have found entry 101"); - } catch (Bookie.NoEntryException e) { - // correct behaviour - } - } - } - - /** - * Test partial index (truncate master key) with post-v3 journals. - */ - @Test - public void testPartialFileInfoPostV3Journal1() throws Exception { - testPartialFileInfoPostV3Journal(true); - } - - /** - * Test partial index with post-v3 journals. - */ - @Test - public void testPartialFileInfoPostV3Journal2() throws Exception { - testPartialFileInfoPostV3Journal(false); - } - - /** - * Test partial index file with post-v3 journals. - */ - private void testPartialFileInfoPostV3Journal(boolean truncateMasterKey) - throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - byte[] masterKey = "testPasswd".getBytes(); - - writeV3Journal(BookieImpl.getCurrentDirectory(journalDir), 100, masterKey); - writePartialIndexFileForLedger(BookieImpl.getCurrentDirectory(ledgerDir), 1, masterKey, - truncateMasterKey); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - BookieImpl b = new TestBookieImpl(conf); - b.readJournal(); - b.readEntry(1, 100); - try { - b.readEntry(1, 101); - fail("Shouldn't have found entry 101"); - } catch (Bookie.NoEntryException e) { - // correct behaviour - } - } - - /** - * Test for fake IOException during read of Journal. - */ - @Test - public void testJournalScanIOException() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - writeV4Journal(BookieImpl.getCurrentDirectory(journalDir), 100, "testPasswd".getBytes()); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - Journal.JournalScanner journalScanner = new DummyJournalScan(); - BookieFileChannel bookieFileChannel = mock(BookieFileChannel.class); - FileChannelProvider fileChannelProvider = mock(FileChannelProvider.class); - - @Cleanup - MockedStatic fileChannelProviderMockedStatic = mockStatic(FileChannelProvider.class); - fileChannelProviderMockedStatic.when(() -> FileChannelProvider.newProvider(any())) - .thenReturn(fileChannelProvider); - doReturn(bookieFileChannel).when(fileChannelProvider).open(any(), any()); - - BookieImpl b = new TestBookieImpl(conf); - - for (Journal journal : b.journals) { - List journalIds = journal.listJournalIds(journal.getJournalDirectory(), null); - - assertEquals(journalIds.size(), 1); - - try { - journal.scanJournal(journalIds.get(0), Long.MAX_VALUE, journalScanner, false); - fail("Should not have been able to scan the journal"); - } catch (Exception e) { - // Expected - } - } - - b.shutdown(); - } - - /** - * Test for invalid record data during read of Journal. - */ - @Test - public void testJournalScanInvalidRecordWithSkipFlag() throws Exception { - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - try { - writeV4JournalWithInvalidRecord(BookieImpl.getCurrentDirectory(journalDir), - 100, "testPasswd".getBytes()); - } catch (Exception e) { - fail(); - } - - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - // Disabled skip broken journal files by default - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null) - .setSkipReplayJournalInvalidRecord(true); - - Journal.JournalScanner journalScanner = new DummyJournalScan(); - - BookieImpl b = new TestBookieImpl(conf); - - for (Journal journal : b.journals) { - List journalIds = Journal.listJournalIds(journal.getJournalDirectory(), null); - assertEquals(journalIds.size(), 1); - try { - journal.scanJournal(journalIds.get(0), 0, journalScanner, conf.isSkipReplayJournalInvalidRecord()); - } catch (Exception e) { - fail("Should pass the journal scanning because we enabled skip flag by default."); - } - } - - b.shutdown(); - - // Disabled skip broken journal files by default - conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setMetadataServiceUri(null); - - journalScanner = new DummyJournalScan(); - - b = new TestBookieImpl(conf); - - for (Journal journal : b.journals) { - List journalIds = Journal.listJournalIds(journal.getJournalDirectory(), null); - assertEquals(journalIds.size(), 1); - try { - journal.scanJournal(journalIds.get(0), 0, journalScanner, conf.isSkipReplayJournalInvalidRecord()); - fail("Should fail the journal scanning because of disabled skip flag"); - } catch (Exception e) { - // expected. - } - } - - b.shutdown(); - } - - - static class DummyJournalScan implements Journal.JournalScanner { - - @Override - public void process(int journalVersion, long offset, ByteBuffer entry) throws IOException { - LOG.warn("Journal Version : " + journalVersion); - } - }; -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieMultipleJournalsTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieMultipleJournalsTest.java deleted file mode 100644 index 664e31541bf..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieMultipleJournalsTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.awaitility.Awaitility; -import org.junit.Test; - -/** - * Test the bookie with multiple journals. - */ -public class BookieMultipleJournalsTest extends BookKeeperClusterTestCase { - - public BookieMultipleJournalsTest() { - super(1); - } - - protected ServerConfiguration newServerConfiguration(int port, File journalDir, - File[] ledgerDirs) { - ServerConfiguration conf = super.newServerConfiguration(port, journalDir, ledgerDirs); - - // Use 4 journals - String[] journalDirs = new String[4]; - for (int i = 0; i < 4; i++) { - journalDirs[i] = journalDir.getAbsolutePath() + "/journal-" + i; - } - conf.setJournalDirsName(journalDirs); - - return conf; - } - - @Test - @SuppressWarnings("unchecked") - public void testJournalExit() throws Exception { - - LedgerHandle ledgerHandle = bkc.createLedger(1, 1, DigestType.CRC32, new byte[0]); - for (int i = 0; i < 10; i++) { - ledgerHandle.addEntry(("entry-" + i).getBytes()); - } - - BookieServer bookieServer = serverByIndex(0); - BookieImpl bookie = (BookieImpl) bookieServer.getBookie(); - Field journalList = bookie.getClass().getDeclaredField("journals"); - journalList.setAccessible(true); - List journals = (List) journalList.get(bookie); - journals.get(0).interruptThread(); - Awaitility.await().untilAsserted(() -> assertFalse(bookie.isRunning())); - } - - @Test - @SuppressWarnings("unchecked") - public void testJournalExitAndShutdown() throws Exception { - - LedgerHandle ledgerHandle = bkc.createLedger(1, 1, DigestType.CRC32, new byte[0]); - for (int i = 0; i < 10; i++) { - ledgerHandle.addEntry(("entry-" + i).getBytes()); - } - - BookieServer bookieServer = serverByIndex(0); - BookieImpl bookie = (BookieImpl) bookieServer.getBookie(); - Field journalList = bookie.getClass().getDeclaredField("journals"); - journalList.setAccessible(true); - List journals = (List) journalList.get(bookie); - journals.get(0).interruptThread(); - bookie.shutdown(ExitCode.OK); - Awaitility.await().untilAsserted(() -> assertFalse(bookie.isRunning())); - } - - @Test - public void testMultipleWritesAndBookieRestart() throws Exception { - // Creates few ledgers so that writes are spread across all journals - final int numLedgers = 16; - final int numEntriesPerLedger = 30; - List writeHandles = new ArrayList<>(); - - for (int i = 0; i < numLedgers; i++) { - writeHandles.add(bkc.createLedger(1, 1, DigestType.CRC32, new byte[0])); - } - - for (int i = 0; i < numEntriesPerLedger; i++) { - for (int j = 0; j < numLedgers; j++) { - writeHandles.get(j).addEntry(("entry-" + i).getBytes()); - } - } - - restartBookies(); - - // Write another set of entries - for (int i = numEntriesPerLedger; i < 2 * numEntriesPerLedger; i++) { - for (int j = 0; j < numLedgers; j++) { - writeHandles.get(j).addEntry(("entry-" + i).getBytes()); - } - } - - restartBookies(); - - List readHandles = new ArrayList<>(); - - for (int i = 0; i < numLedgers; i++) { - readHandles.add(bkc.openLedger(writeHandles.get(i).getId(), DigestType.CRC32, new byte[0])); - } - - for (int i = 0; i < numLedgers; i++) { - Enumeration entries = readHandles.get(i).readEntries(0, numEntriesPerLedger - 1); - - for (int j = 0; j < numEntriesPerLedger; j++) { - LedgerEntry entry = entries.nextElement(); - assertEquals("entry-" + j, new String(entry.getEntry())); - } - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java deleted file mode 100644 index fce3ce8bb30..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Maps; -import java.util.Set; -import java.util.SortedMap; -import java.util.function.Function; -import lombok.Cleanup; -import org.apache.bookkeeper.bookie.BookieShell.MyCommand; -import org.apache.bookkeeper.bookie.BookieShell.RecoverCmd; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.commands.bookie.LastMarkCommand; -import org.apache.bookkeeper.tools.cli.commands.bookies.ClusterInfoCommand; -import org.apache.bookkeeper.tools.cli.commands.bookies.ListBookiesCommand; -import org.apache.bookkeeper.tools.cli.commands.client.SimpleTestCommand; -import org.apache.bookkeeper.tools.cli.commands.client.SimpleTestCommand.Flags; -import org.apache.bookkeeper.tools.framework.CliFlags; -import org.apache.bookkeeper.util.EntryFormatter; -import org.apache.bookkeeper.util.LedgerIdFormatter; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.cli.BasicParser; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.MissingArgumentException; -import org.apache.commons.cli.ParseException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test for {@link BookieShell}. - */ -@RunWith(MockitoJUnitRunner.class) -public class BookieShellTest { - - private ClientConfiguration clientConf; - private BookieShell shell; - private BookKeeperAdmin admin; - private RegistrationManager rm; - private Cookie cookie; - private Version version; - - private ListBookiesCommand.Flags mockListBookiesFlags; - private ListBookiesCommand mockListBookiesCommand; - private MockedStatic listBookiesCommandMockedStatic; - private MockedStatic metadataDriversMockedStatic; - private MockedStatic bookKeeperAdminMockedStatic; - private MockedStatic listBookiesCommandflagsMockedStatic; - - @Before - public void setup() throws Exception { - this.shell = new BookieShell(LedgerIdFormatter.LONG_LEDGERID_FORMATTER, EntryFormatter.STRING_FORMATTER); - - this.mockListBookiesFlags = spy(new ListBookiesCommand.Flags()); - this.listBookiesCommandflagsMockedStatic = mockStatic(ListBookiesCommand.Flags.class); - listBookiesCommandflagsMockedStatic.when(() -> ListBookiesCommand.Flags.newFlags()) - .thenReturn(mockListBookiesFlags); - this.mockListBookiesCommand = spy(new ListBookiesCommand()); - doReturn(true).when(mockListBookiesCommand) - .apply(any(ServerConfiguration.class), any(ListBookiesCommand.Flags.class)); - listBookiesCommandMockedStatic = mockStatic(ListBookiesCommand.class); - listBookiesCommandMockedStatic.when(() -> ListBookiesCommand.newListBookiesCommand(mockListBookiesFlags)) - .thenReturn(mockListBookiesCommand); - - // construct the bookie shell. - this.admin = mock(BookKeeperAdmin.class); - - bookKeeperAdminMockedStatic = mockStatic(BookKeeperAdmin.class); - bookKeeperAdminMockedStatic.when(() -> BookKeeperAdmin.newBookKeeperAdmin(any(ClientConfiguration.class))) - .thenReturn(admin); - this.clientConf = new ClientConfiguration(); - this.clientConf.setMetadataServiceUri("zk://127.0.0.1/path/to/ledgers"); - when(admin.getConf()).thenReturn(this.clientConf); - this.rm = mock(RegistrationManager.class); - this.cookie = Cookie.newBuilder() - .setBookieId("127.0.0.1:3181") - .setInstanceId("xyz") - .setJournalDirs("/path/to/journal/dir") - .setLedgerDirs("/path/to/journal/dir") - .setLayoutVersion(Cookie.CURRENT_COOKIE_LAYOUT_VERSION) - .build(); - this.version = new LongVersion(1L); - when(rm.readCookie(any(BookieId.class))) - .thenReturn(new Versioned<>(cookie.toString().getBytes(UTF_8), version)); - - metadataDriversMockedStatic = mockStatic(MetadataDrivers.class); - metadataDriversMockedStatic - .when(() -> MetadataDrivers.runFunctionWithRegistrationManager( - any(ServerConfiguration.class), any(Function.class))) - .thenAnswer(invocationOnMock -> { - Function function = invocationOnMock.getArgument(1); - function.apply(rm); - return null; - }); - } - - @After - public void teardown() throws Exception { - listBookiesCommandMockedStatic.close(); - listBookiesCommandflagsMockedStatic.close(); - metadataDriversMockedStatic.close(); - bookKeeperAdminMockedStatic.close(); - } - - private static CommandLine parseCommandLine(MyCommand cmd, String... args) throws ParseException { - BasicParser parser = new BasicParser(); - return parser.parse(cmd.getOptions(), args); - } - - @Test - public void testRecoverCmdMissingArgument() throws Exception { - RecoverCmd cmd = (RecoverCmd) shell.commands.get("recover"); - CommandLine cmdLine = parseCommandLine(cmd); - try { - cmd.runCmd(cmdLine); - fail("should fail running command when the arguments are missing"); - } catch (MissingArgumentException e) { - // expected - } - bookKeeperAdminMockedStatic.verify(() -> BookKeeperAdmin.newBookKeeperAdmin(any(ClientConfiguration.class)), - never()); - } - - @Test - public void testRecoverCmdInvalidBookieAddress() throws Exception { - RecoverCmd cmd = (RecoverCmd) shell.commands.get("recover"); - CommandLine cmdLine = parseCommandLine(cmd, "non.valid$$bookie.id"); - assertEquals(-1, cmd.runCmd(cmdLine)); - bookKeeperAdminMockedStatic.verify(() -> BookKeeperAdmin.newBookKeeperAdmin(any(ClientConfiguration.class)), - never()); - } - - @SuppressWarnings("unchecked") - @Test - public void testRecoverCmdQuery() throws Exception { - SortedMap ledgersContainBookies = Maps.newTreeMap(); - when(admin.getLedgersContainBookies(any(Set.class))) - .thenReturn(ledgersContainBookies); - - RecoverCmd cmd = (RecoverCmd) shell.commands.get("recover"); - CommandLine cmdLine = parseCommandLine(cmd, "-force", "-q", "127.0.0.1:3181"); - assertEquals(0, cmd.runCmd(cmdLine)); - bookKeeperAdminMockedStatic.verify(() -> BookKeeperAdmin.newBookKeeperAdmin(any(ClientConfiguration.class)), - times(1)); - verify(admin, times(1)).getLedgersContainBookies(any(Set.class)); - verify(admin, times(1)).close(); - } - - @Test - public void testRecoverCmdRecoverLedgerDefault() throws Exception { - // default behavior - testRecoverCmdRecoverLedger( - 12345, false, false, false, - "-force", "-l", "12345", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverLedgerDeleteCookie() throws Exception { - // dryrun - testRecoverCmdRecoverLedger( - 12345, false, false, true, - "-force", "-l", "12345", "-deleteCookie", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverLedgerSkipOpenLedgersDeleteCookie() throws Exception { - // dryrun - testRecoverCmdRecoverLedger( - 12345, false, true, true, - "-force", "-l", "12345", "-deleteCookie", "-skipOpenLedgers", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverLedgerDryrun() throws Exception { - // dryrun - testRecoverCmdRecoverLedger( - 12345, true, false, false, - "-force", "-l", "12345", "-dryrun", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverLedgerDryrunDeleteCookie() throws Exception { - // dryrun & removeCookie : removeCookie should be false - testRecoverCmdRecoverLedger( - 12345, true, false, false, - "-force", "-l", "12345", "-dryrun", "-deleteCookie", "127.0.0.1:3181"); - } - - @SuppressWarnings("unchecked") - void testRecoverCmdRecoverLedger(long ledgerId, - boolean dryrun, - boolean skipOpenLedgers, - boolean removeCookies, - String... args) throws Exception { - RecoverCmd cmd = (RecoverCmd) shell.commands.get("recover"); - CommandLine cmdLine = parseCommandLine(cmd, args); - assertEquals(0, cmd.runCmd(cmdLine)); - bookKeeperAdminMockedStatic.verify(() -> BookKeeperAdmin.newBookKeeperAdmin(any(ClientConfiguration.class)), - times(1)); - verify(admin, times(1)) - .recoverBookieData(eq(ledgerId), any(Set.class), eq(dryrun), eq(skipOpenLedgers)); - verify(admin, times(1)).close(); - if (removeCookies) { - MetadataDrivers.runFunctionWithRegistrationManager(any(ServerConfiguration.class), any(Function.class)); - verify(rm, times(1)).readCookie(any(BookieId.class)); - verify(rm, times(1)).removeCookie(any(BookieId.class), eq(version)); - } else { - verify(rm, times(0)).readCookie(any(BookieId.class)); - verify(rm, times(0)).removeCookie(any(BookieId.class), eq(version)); - } - } - - @Test - public void testRecoverCmdRecoverDefault() throws Exception { - // default behavior - testRecoverCmdRecover( - false, false, false, false, - "-force", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverDeleteCookie() throws Exception { - // dryrun - testRecoverCmdRecover( - false, false, true, false, - "-force", "-deleteCookie", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverSkipOpenLedgersDeleteCookie() throws Exception { - // dryrun - testRecoverCmdRecover( - false, true, true, false, - "-force", "-deleteCookie", "-skipOpenLedgers", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverDryrun() throws Exception { - // dryrun - testRecoverCmdRecover( - true, false, false, false, - "-force", "-dryrun", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverDryrunDeleteCookie() throws Exception { - // dryrun & removeCookie : removeCookie should be false - testRecoverCmdRecover( - true, false, false, false, - "-force", "-dryrun", "-deleteCookie", "127.0.0.1:3181"); - } - - @Test - public void testRecoverCmdRecoverSkipUnrecoverableLedgers() throws Exception { - // skipUnrecoverableLedgers - testRecoverCmdRecover( - false, false, false, true, - "-force", "-sku", "127.0.0.1:3181"); - } - - @SuppressWarnings("unchecked") - void testRecoverCmdRecover(boolean dryrun, - boolean skipOpenLedgers, - boolean removeCookies, - boolean skipUnrecoverableLedgers, - String... args) throws Exception { - RecoverCmd cmd = (RecoverCmd) shell.commands.get("recover"); - CommandLine cmdLine = parseCommandLine(cmd, args); - assertEquals(0, cmd.runCmd(cmdLine)); - bookKeeperAdminMockedStatic.verify(() -> BookKeeperAdmin.newBookKeeperAdmin(any(ClientConfiguration.class)), - times(1)); - verify(admin, times(1)) - .recoverBookieData(any(Set.class), eq(dryrun), eq(skipOpenLedgers), eq(skipUnrecoverableLedgers)); - verify(admin, times(1)).close(); - if (removeCookies) { - MetadataDrivers.runFunctionWithRegistrationManager(any(ServerConfiguration.class), any(Function.class)); - verify(rm, times(1)).readCookie(any(BookieId.class)); - verify(rm, times(1)).removeCookie(any(BookieId.class), eq(version)); - } else { - verify(rm, times(0)).readCookie(any(BookieId.class)); - verify(rm, times(0)).removeCookie(any(BookieId.class), eq(version)); - } - } - - @Test - public void testLastMarkCmd() throws Exception { - LastMarkCommand mockLastMarkCommand = mock(LastMarkCommand.class); - - @Cleanup - MockedStatic lastMarkCommandMockedStatic = mockStatic(LastMarkCommand.class); - lastMarkCommandMockedStatic.when(() -> LastMarkCommand.newLastMarkCommand()).thenReturn(mockLastMarkCommand); - - shell.run(new String[] { "lastmark"}); - lastMarkCommandMockedStatic.verify(() -> LastMarkCommand.newLastMarkCommand(), times(1)); - verify(mockLastMarkCommand, times(1)) - .apply(same(shell.bkConf), any(CliFlags.class)); - } - - @Test - public void testSimpleTestCmd() throws Exception { - SimpleTestCommand.Flags mockSimpleTestFlags = spy(new SimpleTestCommand.Flags()); - - @Cleanup - MockedStatic flagsMockedStatic = mockStatic(Flags.class); - flagsMockedStatic.when(() -> Flags.newFlags()).thenReturn(mockSimpleTestFlags); - - SimpleTestCommand mockSimpleTestCommand = spy(new SimpleTestCommand()); - doReturn(true).when(mockSimpleTestCommand) - .apply(any(ServerConfiguration.class), any(SimpleTestCommand.Flags.class)); - - @Cleanup - MockedStatic simpleTestCommandMockedStatic = mockStatic(SimpleTestCommand.class); - simpleTestCommandMockedStatic.when(() -> SimpleTestCommand.newSimpleTestCommand(mockSimpleTestFlags)) - .thenReturn(mockSimpleTestCommand); - - shell.run(new String[] { - "simpletest", - "-e", "10", - "-w", "5", - "-a", "3", - "-n", "200" - }); - simpleTestCommandMockedStatic.verify(() -> SimpleTestCommand.newSimpleTestCommand(mockSimpleTestFlags), - times(1)); - verify(mockSimpleTestCommand, times(1)) - .apply(same(shell.bkConf), same(mockSimpleTestFlags)); - verify(mockSimpleTestFlags, times(1)).ensembleSize(eq(10)); - verify(mockSimpleTestFlags, times(1)).writeQuorumSize(eq(5)); - verify(mockSimpleTestFlags, times(1)).ackQuorumSize(eq(3)); - verify(mockSimpleTestFlags, times(1)).numEntries(eq(200)); - } - - @Test - public void testListBookiesCmdNoArgs() throws Exception { - assertEquals(1, shell.run(new String[] { - "listbookies" - })); - - listBookiesCommandMockedStatic.verify(() -> ListBookiesCommand.newListBookiesCommand(mockListBookiesFlags) - , times(0)); - } - - @Test - public void testListBookiesCmdConflictArgs() throws Exception { - assertEquals(1, shell.run(new String[] { - "listbookies", "-rw", "-ro" - })); - listBookiesCommandMockedStatic.verify(() -> ListBookiesCommand.newListBookiesCommand(mockListBookiesFlags), - times(0)); - } - - @Test - public void testListBookiesCmdReadOnly() throws Exception { - assertEquals(0, shell.run(new String[] { - "listbookies", "-ro" - })); - - listBookiesCommandMockedStatic.verify(() -> ListBookiesCommand.newListBookiesCommand(mockListBookiesFlags), - times(1)); - verify(mockListBookiesCommand, times(1)) - .apply(same(shell.bkConf), same(mockListBookiesFlags)); - verify(mockListBookiesFlags, times(1)).readonly(true); - verify(mockListBookiesFlags, times(1)).readwrite(false); - verify(mockListBookiesFlags, times(1)).all(false); - } - - @Test - public void testListBookiesCmdReadWrite() throws Exception { - assertEquals(0, shell.run(new String[] { - "listbookies", "-rw" - })); - listBookiesCommandMockedStatic.verify(() -> ListBookiesCommand.newListBookiesCommand(mockListBookiesFlags), - times(1)); - verify(mockListBookiesCommand, times(1)) - .apply(same(shell.bkConf), same(mockListBookiesFlags)); - verify(mockListBookiesFlags, times(1)).readonly(false); - verify(mockListBookiesFlags, times(1)).readwrite(true); - verify(mockListBookiesFlags, times(1)).all(false); - } - - @Test - public void testListBookiesCmdAll() throws Exception { - assertEquals(0, shell.run(new String[] { - "listbookies", "-a" - })); - listBookiesCommandMockedStatic.verify(() -> ListBookiesCommand.newListBookiesCommand(mockListBookiesFlags), - times(1)); - verify(mockListBookiesCommand, times(1)) - .apply(same(shell.bkConf), same(mockListBookiesFlags)); - verify(mockListBookiesFlags, times(1)).readonly(false); - verify(mockListBookiesFlags, times(1)).readwrite(false); - verify(mockListBookiesFlags, times(1)).all(true); - } - - @Test - public void testForceAuditChecksWithNoArgs() throws Exception { - assertEquals(-1, shell.run(new String[] { - "forceauditchecks" - })); - } - - @Test - public void testForceAuditChecksWithSomeArgs() throws Exception { - assertEquals(0, shell.run(new String[] { - "forceauditchecks", "-calc" - })); - } - - @Test - public void testForceAuditChecksWithAllArgs() throws Exception { - assertEquals(0, shell.run(new String[] { - "forceauditchecks", "-calc", "-rc", "-ppc" - })); - } - - @Test - public void testClusterInfoCmd() throws Exception { - ClusterInfoCommand mockClusterInfoCommand = spy(new ClusterInfoCommand()); - - @Cleanup - MockedStatic clusterInfoCommandMockedStatic = mockStatic(ClusterInfoCommand.class); - clusterInfoCommandMockedStatic.when(() -> ClusterInfoCommand.newClusterInfoCommand()) - .thenReturn(mockClusterInfoCommand); - - doReturn(true).when(mockClusterInfoCommand).apply(same(shell.bkConf), any(CliFlags.class)); - shell.run(new String[]{ "clusterinfo" }); - clusterInfoCommandMockedStatic.verify(() -> ClusterInfoCommand.newClusterInfoCommand(), - times(1)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShutdownTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShutdownTest.java deleted file mode 100644 index 7dd528f04be..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShutdownTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.fail; - -import java.nio.ByteBuffer; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test bookie shutdown. - */ -public class BookieShutdownTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(BookieShutdownTest.class); - - public BookieShutdownTest() { - super(3); - baseConf.setAllowEphemeralPorts(false); - } - - private LedgerHandle lh; - private int numEntriesToWrite = 200; - private int maxInt = 2147483647; - private Random rng = new Random(System.currentTimeMillis()); - private DigestType digestType = DigestType.CRC32; - - class SyncObj { - } - - /** - * Tests verifies the bookkeeper shutdown while writing entries. - * Continuously restarting the bookie server to see all the external - * resources are releasing properly. BOOKKEEPER-678 - */ - @Test - public void testBookieRestartContinuously() throws Exception { - for (int index = 0; index < 10; index++) { - SyncObj sync = new SyncObj(); - try { - // Create a ledger - lh = bkc.createLedger(3, 2, digestType, "aaa".getBytes()); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - lh.asyncAddEntry(entry.array(), - new LedgerEntryAddCallback(), sync); - } - - LOG.info("Wrote " + numEntriesToWrite - + " and now going to fail bookie."); - // Shutdown one Bookie server and restarting new one to continue - // writing - killBookie(0); - startNewBookie(); - LOG.info("Shutdown one bookie server and started new bookie server..."); - } catch (BKException e) { - LOG.error("Caught BKException", e); - fail(e.toString()); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Caught InterruptedException", e); - fail(e.toString()); - } - } - } - - private class LedgerEntryAddCallback implements AddCallback { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, - Object ctx) { - SyncObj x = (SyncObj) ctx; - synchronized (x) { - x.notify(); - } - } - } - - /** - * Test whether Bookie can be shutdown when the call comes inside bookie thread. - * - * @throws Exception - */ - @Test - public void testBookieShutdownFromBookieThread() throws Exception { - ServerConfiguration conf = confByIndex(0); - killBookie(0); - final CountDownLatch latch = new CountDownLatch(1); - final CountDownLatch shutdownComplete = new CountDownLatch(1); - Bookie bookie = new TestBookieImpl(conf) { - @Override - public void run() { - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - // Ignore - } - triggerBookieShutdown(ExitCode.BOOKIE_EXCEPTION); - } - - @Override - synchronized int shutdown(int exitCode) { - super.shutdown(exitCode); - shutdownComplete.countDown(); - return exitCode; - } - }; - bookie.start(); - // after 1 sec stop . - Thread.sleep(1000); - latch.countDown(); - shutdownComplete.await(5000, TimeUnit.MILLISECONDS); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStickyReadsTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStickyReadsTest.java deleted file mode 100644 index 99bcc78845f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStickyReadsTest.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.beust.jcommander.internal.Lists; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Tests of the main BookKeeper client. - */ -@Slf4j -public class BookieStickyReadsTest extends BookKeeperClusterTestCase { - - private static final int NUM_BOOKIES = 3; - - private static final String READ_ENTRY_SCHEDULING_DELAY_METRIC = "bookkeeper_server.READ_ENTRY_SCHEDULING_DELAY"; - - public BookieStickyReadsTest() { - super(NUM_BOOKIES); - } - - @Test - public void testNormalReads() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - - // Default should already be set to false - // conf.setStickyReadsEnabled(false); - - writeAndReadEntries(conf, 3, 3, 3); - - // All bookies should have received at least some read request - getBookieReadEntrySchedulingDelayStats().values() - .forEach(readRequests -> assertTrue(readRequests > 0)); - } - - @Test - public void testStickyFlagWithStriping() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setStickyReadsEnabled(true); - - writeAndReadEntries(conf, 3, 2, 2); - - // All bookies should have received at least some read request since we - // don't enable sticky reads when striping is enabled - getBookieReadEntrySchedulingDelayStats().values() - .forEach(readRequests -> assertTrue(readRequests > 0)); - } - - @Test - public void stickyReadsWithNoFailures() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setStickyReadsEnabled(true); - - writeAndReadEntries(conf, 3, 3, 3); - - // All read requests should have been made to a single bookie - Map stats = getBookieReadEntrySchedulingDelayStats(); - boolean foundBookieWithRequests = false; - for (long readRequests : stats.values()) { - if (readRequests > 0) { - assertFalse("Another bookie already had received requests", foundBookieWithRequests); - foundBookieWithRequests = true; - } - } - } - - @Test - public void stickyReadsWithFailures() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setStickyReadsEnabled(true); - - @Cleanup - BookKeeper bkc = new BookKeeper(conf); - - final int n = 10; - long ledgerId; - - try (WriteHandle wh = bkc.newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(3) - .withPassword("".getBytes()) - .execute() - .join()) { - ledgerId = wh.getId(); - - for (int i = 0; i < n; i++) { - wh.append(("entry-" + i).getBytes()); - } - } - - @Cleanup - ReadHandle rh = bkc.newOpenLedgerOp() - .withLedgerId(ledgerId) - .withPassword("".getBytes()) - .execute() - .join(); - - // Read 1 entry and detect which bookie was being used - @Cleanup - LedgerEntries entry0 = rh.read(0, 0); - assertArrayEquals("entry-0".getBytes(), entry0.getEntry(0).getEntryBytes()); - - // All read requests should have been made to a single bookie - int bookieWithRequests = -1; - for (int i = 0; i < NUM_BOOKIES; i++) { - long requests = getStatsProvider(i).getOpStatsLogger(READ_ENTRY_SCHEDULING_DELAY_METRIC) - .getSuccessCount(); - - log.info("Bookie {} --- requests: {}", i, requests); - - if (requests > 0) { - assertTrue("Another bookie already had received requests", bookieWithRequests == -1); - bookieWithRequests = i; - } - } - - // Suspend the sticky bookie. Reads should now go to a different sticky - // bookie - serverByIndex(bookieWithRequests).suspendProcessing(); - - for (int i = 0; i < n; i++) { - @Cleanup - LedgerEntries entries = rh.read(i, i); - - assertArrayEquals(("entry-" + i).getBytes(), entries.getEntry(i).getEntryBytes()); - } - - // At this point, we should have 1 bookie with 1 request (the initial - // request), and a second bookie with 10 requests. The 3rd bookie should - // have no requests - List requestCounts = Lists.newArrayList(getBookieReadEntrySchedulingDelayStats().values()); - Collections.sort(requestCounts); - - assertEquals(0, requestCounts.get(0).longValue()); - assertEquals(1, requestCounts.get(1).longValue()); - assertEquals(10, requestCounts.get(2).longValue()); - } - private Map getBookieReadEntrySchedulingDelayStats() throws Exception { - Map stats = new TreeMap<>(); - for (int i = 0; i < NUM_BOOKIES; i++) { - stats.put(i, getStatsProvider(i).getOpStatsLogger(READ_ENTRY_SCHEDULING_DELAY_METRIC) - .getSuccessCount()); - } - - return stats; - } - - private void writeAndReadEntries(ClientConfiguration conf, int ensembleSize, int writeQuorum, int ackQuorum) - throws Exception { - @Cleanup - BookKeeper bkc = new BookKeeper(conf); - - @Cleanup - WriteHandle wh = bkc.newCreateLedgerOp() - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorum) - .withAckQuorumSize(ackQuorum) - .withPassword("".getBytes()) - .execute() - .join(); - - final int n = 10; - - for (int i = 0; i < n; i++) { - wh.append(("entry-" + i).getBytes()); - } - - for (int i = 0; i < n; i++) { - @Cleanup - LedgerEntries entries = wh.read(i, i); - - assertArrayEquals(("entry-" + i).getBytes(), entries.getEntry(i).getEntryBytes()); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStorageThresholdTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStorageThresholdTest.java deleted file mode 100644 index b242a0d8663..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStorageThresholdTest.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.File; -import java.util.Collections; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.bookie.LedgerDirsManager.LedgerDirsListener; -import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.TestUtils; -import org.junit.Before; - -/** - * Test BookieStorage with a threshold. - */ -public class BookieStorageThresholdTest extends BookKeeperClusterTestCase { - - private static final int NUM_BOOKIES = 1; - private static final int NUM_ENTRIES = 100; - private static final int ENTRY_SIZE = 1024; - - final String msg; - DigestType digestType = DigestType.CRC32; - - public BookieStorageThresholdTest() { - super(NUM_BOOKIES); - // a dummy message - StringBuilder msgSB = new StringBuilder(); - for (int i = 0; i < ENTRY_SIZE; i++) { - msgSB.append("a"); - } - msg = msgSB.toString(); - } - - @Before - @Override - public void setUp() throws Exception { - // Set up the configuration properties needed. - baseConf.setEntryLogSizeLimit(NUM_ENTRIES * ENTRY_SIZE); - baseConf.setFlushInterval(500); - // setting very high intervals for GC intervals, so GC/compaction is not invoked by regular scheduler - baseConf.setGcWaitTime(60000); - baseConf.setMinorCompactionInterval(600000); - baseConf.setMajorCompactionInterval(700000); - baseConf.setEntryLogFilePreAllocationEnabled(false); - baseConf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - // set isForceGCAllowWhenNoSpace to true, which will forceGC when a disk is full (or when all disks are full) - baseConf.setIsForceGCAllowWhenNoSpace(true); - // keep some lower value for DiskCheckInterval, so DiskChecker checks quite often - baseConf.setDiskCheckInterval(3000); - - super.setUp(); - } - - LedgerHandle[] prepareData(int numEntryLogs) throws Exception { - // since an entry log file can hold at most 100 entries - // first ledger write 2 entries, which is less than low water mark - int num1 = 2; - // third ledger write more than high water mark entries - int num3 = (int) (NUM_ENTRIES * 0.7f); - // second ledger write remaining entries, which is higher than low water - // mark and less than high water mark - int num2 = NUM_ENTRIES - num3 - num1; - - LedgerHandle[] lhs = new LedgerHandle[3]; - for (int i = 0; i < 3; ++i) { - lhs[i] = bkc.createLedger(NUM_BOOKIES, NUM_BOOKIES, digestType, "".getBytes()); - } - - for (int n = 0; n < numEntryLogs; n++) { - for (int k = 0; k < num1; k++) { - lhs[0].addEntry(msg.getBytes()); - } - for (int k = 0; k < num2; k++) { - lhs[1].addEntry(msg.getBytes()); - } - for (int k = 0; k < num3; k++) { - lhs[2].addEntry(msg.getBytes()); - } - } - - return lhs; - } - - /** - * A Threshold-based disk checker test. - */ - public class ThresholdTestDiskChecker extends DiskChecker { - - final AtomicBoolean injectDiskOutOfSpaceException; - - public ThresholdTestDiskChecker(float threshold, float warnThreshold) { - super(threshold, warnThreshold); - injectDiskOutOfSpaceException = new AtomicBoolean(); - } - - public void setInjectDiskOutOfSpaceException(boolean setValue) { - injectDiskOutOfSpaceException.set(setValue); - } - - @Override - public float checkDir(File dir) throws DiskErrorException, DiskOutOfSpaceException, DiskWarnThresholdException { - if (injectDiskOutOfSpaceException.get()) { - throw new DiskOutOfSpaceException("Injected DiskOutOfSpaceException", - baseConf.getDiskUsageThreshold() + 2); - } - return super.checkDir(dir); - } - } - - @FlakyTest(value = "https://github.com/apache/bookkeeper/issues/1562") - public void testStorageThresholdCompaction() throws Exception { - stopAllBookies(); - ServerConfiguration conf = newServerConfiguration(); - File ledgerDir1 = tmpDirs.createNew("ledger", "test1"); - File ledgerDir2 = tmpDirs.createNew("ledger", "test2"); - File journalDir = tmpDirs.createNew("journal", "test"); - String[] ledgerDirNames = new String[]{ - ledgerDir1.getPath(), - ledgerDir2.getPath() - }; - conf.setLedgerDirNames(ledgerDirNames); - conf.setJournalDirName(journalDir.getPath()); - - BookieServer server = startAndAddBookie(conf).getServer(); - BookieImpl bookie = (BookieImpl) server.getBookie(); - // since we are going to set dependency injected dirsMonitor, so we need to shutdown - // the dirsMonitor which was created as part of the initialization of Bookie - bookie.dirsMonitor.shutdown(); - - LedgerDirsManager ledgerDirsManager = ((BookieImpl) bookie).getLedgerDirsManager(); - - // flag latches - final CountDownLatch diskWritable = new CountDownLatch(1); - final CountDownLatch diskFull = new CountDownLatch(1); - ledgerDirsManager.addLedgerDirsListener(new LedgerDirsListener() { - - @Override - public void diskWritable(File disk) { - diskWritable.countDown(); - } - - @Override - public void diskFull(File disk) { - diskFull.countDown(); - } - - }); - - // Dependency Injected class - ThresholdTestDiskChecker thresholdTestDiskChecker = new ThresholdTestDiskChecker( - baseConf.getDiskUsageThreshold(), baseConf.getDiskUsageWarnThreshold()); - bookie.dirsMonitor = new LedgerDirsMonitor(baseConf, thresholdTestDiskChecker, - Collections.singletonList(ledgerDirsManager)); - // set the dirsMonitor and initiate/start it - bookie.dirsMonitor.init(); - bookie.dirsMonitor.start(); - - // create ledgers and add fragments - LedgerHandle[] lhs = prepareData(3); - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // delete ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - // validating that LedgerDirsListener are not triggered yet - assertTrue("Disk Full shouldn't have been triggered yet", diskFull.getCount() == 1); - assertTrue("Disk writable shouldn't have been triggered yet", diskWritable.getCount() == 1); - // set exception injection to true, so that next time when checkDir of DiskChecker (ThresholdTestDiskChecker) is - // called it will throw DiskOutOfSpaceException - thresholdTestDiskChecker.setInjectDiskOutOfSpaceException(true); - - // now we are waiting for diskFull latch count to get to 0. - // we are waiting for diskCheckInterval period, so that next time when LedgerDirsMonitor monitors diskusage of - // its directories, it would get DiskOutOfSpaceException and hence diskFull of all LedgerDirsListener would be - // called. - diskFull.await(baseConf.getDiskCheckInterval() + 500, TimeUnit.MILLISECONDS); - // verifying that diskFull of all LedgerDirsListener are invoked, so countdown of diskFull should come down to 0 - assertTrue("Disk Full should have been triggered", diskFull.getCount() == 0); - // making sure diskWritable of LedgerDirsListener are not invoked yet - assertTrue("Disk writable shouldn't have been triggered yet", diskWritable.getCount() == 1); - // waiting momentarily, because transition to Readonly mode happens asynchronously when there are no more - // writableLedgerDirs - Thread.sleep(500); - assertTrue("Bookie should be transitioned to ReadOnly", bookie.isReadOnly()); - // since we set isForceGCAllowWhenNoSpace to true, when the disk is full (or when all disks are full) it does - // force GC. - // Because of getWritableLedgerDirsForNewLog, compaction would be able to create newlog and compact even though - // there are no writableLedgerDirs - for (File ledgerDir : bookie.getLedgerDirsManager().getAllLedgerDirs()) { - assertFalse("Found entry log file ([0,1,2].log. They should have been compacted" + ledgerDir, - TestUtils.hasLogFiles(ledgerDir.getParentFile(), true, 0, 1, 2)); - } - - try { - ledgerDirsManager.getWritableLedgerDirs(); - fail("It is expected that there wont be any Writable LedgerDirs and getWritableLedgerDirs " - + "is supposed to throw NoWritableLedgerDirException"); - } catch (NoWritableLedgerDirException nowritableDirsException) { - } - - // disable exception injection - thresholdTestDiskChecker.setInjectDiskOutOfSpaceException(false); - - // now we are waiting for diskWritable latch count to get to 0. - // we are waiting for diskCheckInterval period, so that next time when LedgerDirsMonitor monitors diskusage of - // its directories, it would find writableledgerdirectory and hence diskWritable of all LedgerDirsListener would - // be called. - diskWritable.await(baseConf.getDiskCheckInterval() + 500, TimeUnit.MILLISECONDS); - // verifying that diskWritable of all LedgerDirsListener are invoked, so countdown of diskWritable should come - // down to 0 - assertTrue("Disk writable should have been triggered", diskWritable.getCount() == 0); - // waiting momentarily, because transition to ReadWrite mode happens asynchronously when there is new - // writableLedgerDirectory - Thread.sleep(500); - assertFalse("Bookie should be transitioned to ReadWrite", bookie.isReadOnly()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieThreadTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieThreadTest.java deleted file mode 100644 index 1f237f7249a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieThreadTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.junit.Assert; -import org.junit.Test; - -/** - * Testing bookie thread cases. - */ -public class BookieThreadTest { - - private CountDownLatch runningLatch = new CountDownLatch(1); - - /** - * A BookieThread implementation. - */ - public class MyThread extends BookieThread { - - public MyThread(String threadName) { - super(threadName); - } - - public void run() { - throw new Error(); - } - - @Override - protected void handleException(Thread t, Throwable e) { - Assert.assertEquals("Unknown thread!", this, t); - runningLatch.countDown(); - } - } - - /** - * A critical thread implementation. - */ - public class MyCriticalThread extends BookieCriticalThread { - - public MyCriticalThread(String threadName) { - super(threadName); - } - - public void run() { - throw new Error(); - } - - @Override - protected void handleException(Thread t, Throwable e) { - Assert.assertEquals("Unknown thread!", this, t); - runningLatch.countDown(); - } - } - - /** - * Test verifies uncaught exception handling of BookieThread. - */ - @Test - public void testUncaughtException() throws Exception { - MyThread myThread = new MyThread("Test-Thread"); - myThread.start(); - Assert.assertTrue("Uncaught exception is not properly handled.", - runningLatch.await(10000, TimeUnit.MILLISECONDS)); - - runningLatch = new CountDownLatch(1); - MyCriticalThread myCriticalThread = new MyCriticalThread( - "Test-Critical-Thread"); - myCriticalThread.start(); - Assert.assertTrue("Uncaught exception is not properly handled.", - runningLatch.await(10000, TimeUnit.MILLISECONDS)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieWriteToJournalTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieWriteToJournalTest.java deleted file mode 100644 index 0907a625282..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieWriteToJournalTest.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.complete; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.api.BKException; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.lang3.mutable.MutableBoolean; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; - -/** - * Test the bookie journal. - */ -@RunWith(MockitoJUnitRunner.Silent.class) -@Slf4j -public class BookieWriteToJournalTest { - - @Rule - public TemporaryFolder tempDir = new TemporaryFolder(); - - class NoOpJournalReplayBookie extends TestBookieImpl { - - public NoOpJournalReplayBookie(ServerConfiguration conf) - throws Exception { - super(conf); - } - - @Override - void readJournal() throws IOException, BookieException { - // Should be no-op since journal objects are mocked - } - } - - /** - * test that Bookie calls correctly Journal.logAddEntry about "ackBeforeSync" parameter. - */ - - @Test - public void testJournalLogAddEntryCalledCorrectly() throws Exception { - - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - File ledgerDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir.getPath()}) - .setMetadataServiceUri(null); - - BookieId bookieAddress = BookieImpl.getBookieId(conf); - CountDownLatch journalJoinLatch = new CountDownLatch(1); - Journal journal = mock(Journal.class); - MutableBoolean effectiveAckBeforeSync = new MutableBoolean(false); - doAnswer((Answer) (InvocationOnMock iom) -> { - ByteBuf entry = iom.getArgument(0); - long ledgerId = entry.getLong(entry.readerIndex() + 0); - long entryId = entry.getLong(entry.readerIndex() + 8); - boolean ackBeforeSync = iom.getArgument(1); - WriteCallback callback = iom.getArgument(2); - Object ctx = iom.getArgument(3); - - effectiveAckBeforeSync.setValue(ackBeforeSync); - callback.writeComplete(BKException.Code.OK, ledgerId, entryId, bookieAddress, ctx); - return null; - }).when(journal).logAddEntry(any(ByteBuf.class), anyBoolean(), any(WriteCallback.class), any()); - - // bookie will continue to work as soon as the journal thread is alive - doAnswer((Answer) (InvocationOnMock iom) -> { - journalJoinLatch.await(); - return null; - }).when(journal).joinThread(); - - @Cleanup - MockedStatic journalMockedStatic = mockStatic(Journal.class); - journalMockedStatic.when(() -> Journal.newJournal(anyInt(), any(), any(), any(), any(), any(), any())) - .thenReturn(journal); - - Bookie b = new NoOpJournalReplayBookie(conf); - b.start(); - - long ledgerId = 1; - long entryId = 0; - Object expectedCtx = "foo"; - byte[] masterKey = new byte[64]; - for (boolean ackBeforeSync : new boolean[]{true, false}) { - CountDownLatch latch = new CountDownLatch(1); - final ByteBuf data = buildEntry(ledgerId, entryId, -1); - final long expectedEntryId = entryId; - b.addEntry(data, ackBeforeSync, (int rc, long ledgerId1, long entryId1, - BookieId addr, Object ctx) -> { - assertSame(expectedCtx, ctx); - assertEquals(ledgerId, ledgerId1); - assertEquals(expectedEntryId, entryId1); - latch.countDown(); - }, expectedCtx, masterKey); - latch.await(30, TimeUnit.SECONDS); - assertEquals(ackBeforeSync, effectiveAckBeforeSync.booleanValue()); - entryId++; - } - // let bookie exit main thread - journalJoinLatch.countDown(); - b.shutdown(); - } - - /** - * test that Bookie calls correctly Journal.forceLedger and is able to return the correct LastAddPersisted entry id. - */ - @Test - public void testForceLedger() throws Exception { - - File journalDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - File ledgerDir = tempDir.newFolder(); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir.getPath()}); - - Bookie b = new TestBookieImpl(conf); - b.start(); - - long ledgerId = 1; - long entryId = 0; - Object expectedCtx = "foo"; - byte[] masterKey = new byte[64]; - - CompletableFuture latchForceLedger1 = new CompletableFuture<>(); - CompletableFuture latchForceLedger2 = new CompletableFuture<>(); - CompletableFuture latchAddEntry = new CompletableFuture<>(); - final ByteBuf data = buildEntry(ledgerId, entryId, -1); - final long expectedEntryId = entryId; - b.forceLedger(ledgerId, (int rc, long ledgerId1, long entryId1, - BookieId addr, Object ctx) -> { - if (rc != BKException.Code.OK) { - latchForceLedger1.completeExceptionally(org.apache.bookkeeper.client.BKException.create(rc)); - return; - } - complete(latchForceLedger1, null); - }, expectedCtx); - result(latchForceLedger1); - - b.addEntry(data, true /* ackBeforesync */, (int rc, long ledgerId1, long entryId1, - BookieId addr, Object ctx) -> { - if (rc != BKException.Code.OK) { - latchAddEntry.completeExceptionally(org.apache.bookkeeper.client.BKException.create(rc)); - return; - } - latchAddEntry.complete(entryId); - }, expectedCtx, masterKey); - assertEquals(expectedEntryId, result(latchAddEntry).longValue()); - - // issue a new "forceLedger" - b.forceLedger(ledgerId, (int rc, long ledgerId1, long entryId1, - BookieId addr, Object ctx) -> { - if (rc != BKException.Code.OK) { - latchForceLedger2.completeExceptionally(org.apache.bookkeeper.client.BKException.create(rc)); - return; - } - complete(latchForceLedger2, null); - }, expectedCtx); - result(latchForceLedger2); - - b.shutdown(); - } - - @Test - public void testSmallJournalQueueWithHighFlushFrequency() throws IOException, InterruptedException { - ServerConfiguration conf = new ServerConfiguration(); - conf.setJournalQueueSize(1); - conf.setJournalFlushWhenQueueEmpty(true); - conf.setJournalBufferedWritesThreshold(1); - - conf.setJournalDirName(tempDir.newFolder().getPath()); - conf.setLedgerDirNames(new String[]{tempDir.newFolder().getPath()}); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), diskChecker); - Journal journal = new Journal(0, conf.getJournalDirs()[0], conf, ledgerDirsManager); - journal.start(); - - final int entries = 1000; - CountDownLatch entriesLatch = new CountDownLatch(entries); - for (int j = 1; j <= entries; j++) { - ByteBuf entry = buildEntry(1, j, -1); - journal.logAddEntry(entry, false, (int rc, long ledgerId, long entryId, BookieId addr, Object ctx) -> { - entriesLatch.countDown(); - }, null); - } - entriesLatch.await(); - - journal.shutdown(); - } - - private static ByteBuf buildEntry(long ledgerId, long entryId, long lastAddConfirmed) { - final ByteBuf data = Unpooled.buffer(); - data.writeLong(ledgerId); - data.writeLong(entryId); - data.writeLong(lastAddConfirmed); - return data; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BufferedChannelTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BufferedChannelTest.java deleted file mode 100644 index cd3e34d35e3..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BufferedChannelTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.util.Random; -import org.junit.Assert; -import org.junit.Test; - -/** - * Tests for BufferedChannel. - */ -public class BufferedChannelTest { - - private static Random rand = new Random(); - private static final int INTERNAL_BUFFER_WRITE_CAPACITY = 65536; - private static final int INTERNAL_BUFFER_READ_CAPACITY = 512; - - @Test - public void testBufferedChannelWithNoBoundOnUnpersistedBytes() throws Exception { - testBufferedChannel(5000, 30, 0, false, false); - } - - @Test - public void testBufferedChannelWithBoundOnUnpersistedBytes() throws Exception { - testBufferedChannel(5000, 30, 5000 * 28, false, false); - } - - @Test - public void testBufferedChannelWithBoundOnUnpersistedBytesAndFlush() throws Exception { - testBufferedChannel(5000, 30, 5000 * 28, true, false); - } - - @Test - public void testBufferedChannelFlushNoForceWrite() throws Exception { - testBufferedChannel(5000, 30, 0, true, false); - } - - @Test - public void testBufferedChannelForceWriteNoFlush() throws Exception { - testBufferedChannel(5000, 30, 0, false, true); - } - - @Test - public void testBufferedChannelFlushForceWrite() throws Exception { - testBufferedChannel(5000, 30, 0, true, true); - } - - public void testBufferedChannel(int byteBufLength, int numOfWrites, int unpersistedBytesBound, boolean flush, - boolean shouldForceWrite) throws Exception { - File newLogFile = File.createTempFile("test", "log"); - newLogFile.deleteOnExit(); - FileChannel fileChannel = new RandomAccessFile(newLogFile, "rw").getChannel(); - - BufferedChannel logChannel = new BufferedChannel(UnpooledByteBufAllocator.DEFAULT, fileChannel, - INTERNAL_BUFFER_WRITE_CAPACITY, INTERNAL_BUFFER_READ_CAPACITY, unpersistedBytesBound); - - ByteBuf dataBuf = generateEntry(byteBufLength); - dataBuf.markReaderIndex(); - dataBuf.markWriterIndex(); - - for (int i = 0; i < numOfWrites; i++) { - logChannel.write(dataBuf); - dataBuf.resetReaderIndex(); - dataBuf.resetWriterIndex(); - } - - if (flush && shouldForceWrite) { - logChannel.flushAndForceWrite(false); - } else if (flush) { - logChannel.flush(); - } else if (shouldForceWrite) { - logChannel.forceWrite(false); - } - - int expectedNumOfUnpersistedBytes = 0; - - if (flush && shouldForceWrite) { - /* - * if flush call is made with shouldForceWrite, - * then expectedNumOfUnpersistedBytes should be zero. - */ - expectedNumOfUnpersistedBytes = 0; - } else if (!flush && shouldForceWrite) { - /* - * if flush is not called then internal write buffer is not flushed, - * but while adding entries to BufferedChannel if writeBuffer has - * reached its capacity then it will call flush method, and the data - * gets added to the file buffer. So though explicitly we are not - * calling flush method, implicitly flush gets called when - * writeBuffer reaches its capacity. - */ - expectedNumOfUnpersistedBytes = (byteBufLength * numOfWrites) % INTERNAL_BUFFER_WRITE_CAPACITY; - } else { - expectedNumOfUnpersistedBytes = (byteBufLength * numOfWrites) - unpersistedBytesBound; - } - - if (unpersistedBytesBound > 0) { - Assert.assertEquals("Unpersisted bytes", expectedNumOfUnpersistedBytes, logChannel.getUnpersistedBytes()); - } - logChannel.close(); - fileChannel.close(); - } - - private static ByteBuf generateEntry(int length) { - byte[] data = new byte[length]; - ByteBuf bb = Unpooled.buffer(length); - rand.nextBytes(data); - bb.writeBytes(data); - return bb; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CheckpointOnNewLedgersTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CheckpointOnNewLedgersTest.java deleted file mode 100644 index be8ad075d5b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CheckpointOnNewLedgersTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCountUtil; -import java.io.File; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ThreadLocalRandom; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.Journal.LastLogMark; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Test the checkpoint logic of {@link DbLedgerStorage}. - */ -@Slf4j -public class CheckpointOnNewLedgersTest { - - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - - private ServerConfiguration conf; - private BookieImpl bookie; - private CountDownLatch getLedgerDescCalledLatch; - private CountDownLatch getLedgerDescWaitLatch; - - @Before - public void setup() throws Exception { - File bkDir = testDir.newFolder("dbLedgerStorageCheckpointTest"); - File curDir = BookieImpl.getCurrentDirectory(bkDir); - BookieImpl.checkDirectoryStructure(curDir); - - int gcWaitTime = 1000; - conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - conf.setJournalDirsName(new String[] { bkDir.toString() }); - conf.setLedgerDirNames(new String[] { bkDir.toString() }); - conf.setEntryLogSizeLimit(10 * 1024); - - bookie = spy(new TestBookieImpl(conf)); - bookie.start(); - - getLedgerDescCalledLatch = new CountDownLatch(1); - getLedgerDescWaitLatch = new CountDownLatch(1); - - // spy `getLedgerForEntry` - doAnswer(invocationOnMock -> { - ByteBuf entry = invocationOnMock.getArgument(0); - long ledgerId = entry.getLong(entry.readerIndex()); - - LedgerDescriptor ld = (LedgerDescriptor) invocationOnMock.callRealMethod(); - - if (ledgerId % 2 == 1) { - getLedgerDescCalledLatch.countDown(); - getLedgerDescWaitLatch.await(); - } - - return ld; - }).when(bookie).getLedgerForEntry( - any(ByteBuf.class), - any(byte[].class)); - } - - @After - public void teardown() throws Exception { - if (null != bookie) { - bookie.shutdown(); - } - } - - private static ByteBuf createByteBuf(long ledgerId, long entryId, int entrySize) { - byte[] data = new byte[entrySize]; - ThreadLocalRandom.current().nextBytes(data); - ByteBuf buffer = Unpooled.wrappedBuffer(data); - buffer.writerIndex(0); - buffer.writeLong(ledgerId); - buffer.writeLong(entryId); - buffer.writeLong(entryId - 1); // lac - buffer.writerIndex(entrySize); - return buffer; - } - - @Test - public void testCheckpoint() throws Exception { - int entrySize = 1024; - long l1 = 1L; - long l2 = 2L; - - final CountDownLatch writeL1Latch = new CountDownLatch(1); - - Thread t1 = new Thread(() -> { - - ByteBuf entry = createByteBuf(l1, 0L, entrySize); - try { - bookie.addEntry( - entry, - false, - (rc, ledgerId, entryId, addr, ctx) -> writeL1Latch.countDown(), - null, - new byte[0] - ); - } catch (Exception e) { - log.info("Failed to write entry to l1", e); - } - - }, "ledger-1-writer"); - - t1.start(); - - // wait until the ledger desc is opened - getLedgerDescCalledLatch.await(); - - LastLogMark logMark = bookie.journals.get(0).getLastLogMark().markLog(); - - // keep write entries to l2 to trigger entry log rolling to checkpoint - int numEntries = 10; - final CountDownLatch writeL2Latch = new CountDownLatch(numEntries); - for (int i = 0; i < numEntries; i++) { - ByteBuf entry = createByteBuf(l2, i, entrySize); - bookie.addEntry( - entry, - false, - (rc, ledgerId, entryId, addr, ctx) -> writeL2Latch.countDown(), - null, - new byte[0]); - } - writeL2Latch.await(); - - // wait until checkpoint to complete and journal marker is rolled. - bookie.syncThread.getExecutor().submit(() -> {}).get(); - - log.info("Wait until checkpoint is completed"); - - // the journal mark is rolled. - LastLogMark newLogMark = bookie.journals.get(0).getLastLogMark().markLog(); - assertTrue(newLogMark.getCurMark().compare(logMark.getCurMark()) > 0); - - // resume l1-writer to continue writing the entries - getLedgerDescWaitLatch.countDown(); - - // wait until the l1 entry is written - writeL1Latch.await(); - t1.join(); - - // construct a new bookie to simulate "bookie restart from crash" - Bookie newBookie = new TestBookieImpl(conf); - newBookie.start(); - - for (int i = 0; i < numEntries; i++) { - ByteBuf entry = newBookie.readEntry(l2, i); - assertNotNull(entry); - assertEquals(l2, entry.readLong()); - assertEquals((long) i, entry.readLong()); - ReferenceCountUtil.release(entry); - } - - ByteBuf entry = newBookie.readEntry(l1, 0L); - assertNotNull(entry); - assertEquals(l1, entry.readLong()); - assertEquals(0L, entry.readLong()); - ReferenceCountUtil.release(entry); - newBookie.shutdown(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ClusterInfoCommandTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ClusterInfoCommandTest.java deleted file mode 100644 index 2e1bb55ce1b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ClusterInfoCommandTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.tools.cli.commands.bookies.ClusterInfoCommand; -import org.apache.bookkeeper.tools.framework.CliFlags; -import org.junit.Test; - -/** - * Integration test of {@link org.apache.bookkeeper.tools.cli.commands.bookies.ClusterInfoCommand}. - */ -public class ClusterInfoCommandTest extends BookKeeperClusterTestCase { - - public ClusterInfoCommandTest() { - super(1); - } - - @Test - public void testClusterInfo() throws Exception { - ClusterInfoCommand clusterInfoCommand = new ClusterInfoCommand(); - final ServerConfiguration conf = confByIndex(0); - - assertNull(clusterInfoCommand.info()); - - clusterInfoCommand.apply(conf, new CliFlags()); - - assertNotNull(clusterInfoCommand.info()); - ClusterInfoCommand.ClusterInfo info = clusterInfoCommand.info(); - assertEquals(1, info.getTotalBookiesCount()); - assertEquals(1, info.getWritableBookiesCount()); - assertEquals(0, info.getReadonlyBookiesCount()); - assertEquals(0, info.getUnavailableBookiesCount()); - assertFalse(info.isAuditorElected()); - assertEquals("", info.getAuditorId()); - assertFalse(info.isClusterUnderReplicated()); - assertTrue(info.isLedgerReplicationEnabled()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithMetadataCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithMetadataCacheTest.java deleted file mode 100644 index 8f22f625175..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithMetadataCacheTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -/** - * Test compaction by bytes. - */ -public class CompactionByBytesWithMetadataCacheTest extends CompactionTest { - public CompactionByBytesWithMetadataCacheTest() { - super(true, true); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithoutMetadataCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithoutMetadataCacheTest.java deleted file mode 100644 index 7b1418dab94..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithoutMetadataCacheTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -/** - * Test compaction by bytes. - */ -public class CompactionByBytesWithoutMetadataCacheTest extends CompactionTest { - public CompactionByBytesWithoutMetadataCacheTest() { - super(true, false); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithMetadataCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithMetadataCacheTest.java deleted file mode 100644 index 86a1f3bd980..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithMetadataCacheTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -/** - * Test compactions by entries. - */ -public class CompactionByEntriesWithMetadataCacheTest extends CompactionTest { - public CompactionByEntriesWithMetadataCacheTest() { - super(false, true); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithoutMetadataCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithoutMetadataCacheTest.java deleted file mode 100644 index 2a02eb26b05..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithoutMetadataCacheTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -/** - * Test compactions by entries. - */ -public class CompactionByEntriesWithoutMetadataCacheTest extends CompactionTest { - public CompactionByEntriesWithoutMetadataCacheTest() { - super(false, false); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionTest.java deleted file mode 100644 index e8982bf0e46..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionTest.java +++ /dev/null @@ -1,1950 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.ACTIVE_ENTRY_LOG_COUNT; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.ACTIVE_ENTRY_LOG_SPACE_BYTES; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.MAJOR_COMPACTION_COUNT; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.MINOR_COMPACTION_COUNT; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.RECLAIMED_COMPACTION_SPACE_BYTES; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.RECLAIMED_DELETION_SPACE_BYTES; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.THREAD_RUNTIME; -import static org.apache.bookkeeper.bookie.TransactionalEntryLogCompactor.COMPACTED_SUFFIX; -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.util.concurrent.UncheckedExecutionException; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import org.apache.bookkeeper.bookie.BookieException.EntryLogMetadataMapException; -import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; -import org.apache.bookkeeper.bookie.storage.CompactionEntryLog; -import org.apache.bookkeeper.bookie.storage.ldb.PersistentEntryLogMetadataMap; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.LedgerMetadataListener; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.Processor; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.TestUtils; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.zookeeper.AsyncCallback; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class tests the entry log compaction functionality. - */ -public abstract class CompactionTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(CompactionTest.class); - - private static final int ENTRY_SIZE = 1024; - private static final int NUM_BOOKIES = 1; - - private final boolean isThrottleByBytes; - private final DigestType digestType; - private final byte[] passwdBytes; - private final int numEntries; - private final int gcWaitTime; - private final double minorCompactionThreshold; - private final double majorCompactionThreshold; - private final long minorCompactionInterval; - private final long majorCompactionInterval; - private final String msg; - private final boolean useMetadataCache; - - public CompactionTest(boolean isByBytes, boolean useMetadataCache) { - super(NUM_BOOKIES); - - this.isThrottleByBytes = isByBytes; - this.useMetadataCache = useMetadataCache; - this.digestType = DigestType.CRC32; - this.passwdBytes = "".getBytes(); - numEntries = 100; - gcWaitTime = 1000; - minorCompactionThreshold = 0.1f; - majorCompactionThreshold = 0.5f; - minorCompactionInterval = 2 * gcWaitTime / 1000; - majorCompactionInterval = 4 * gcWaitTime / 1000; - - // a dummy message - StringBuilder msgSB = new StringBuilder(); - for (int i = 0; i < ENTRY_SIZE; i++) { - msgSB.append("a"); - } - msg = msgSB.toString(); - } - - @Before - @Override - public void setUp() throws Exception { - // Set up the configuration properties needed. - baseConf.setEntryLogSizeLimit(numEntries * ENTRY_SIZE); - // Disable skip list for compaction - baseConf.setGcWaitTime(gcWaitTime); - baseConf.setFlushInterval(100); - baseConf.setMinorCompactionThreshold(minorCompactionThreshold); - baseConf.setMajorCompactionThreshold(majorCompactionThreshold); - baseConf.setMinorCompactionInterval(minorCompactionInterval); - baseConf.setMajorCompactionInterval(majorCompactionInterval); - baseConf.setEntryLogFilePreAllocationEnabled(false); - baseConf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - baseConf.setIsThrottleByBytes(this.isThrottleByBytes); - baseConf.setIsForceGCAllowWhenNoSpace(false); - baseConf.setGcEntryLogMetadataCacheEnabled(useMetadataCache); - super.setUp(); - } - - private GarbageCollectorThread getGCThread() throws Exception { - assertEquals(1, bookieCount()); - BookieServer server = serverByIndex(0); - return ((InterleavedLedgerStorage) server.getBookie().getLedgerStorage()).gcThread; - } - - LedgerHandle[] prepareData(int numEntryLogs, boolean changeNum) - throws Exception { - // since an entry log file can hold at most 100 entries - // first ledger write 2 entries, which is less than low water mark - int num1 = 2; - // third ledger write more than high water mark entries - int num3 = (int) (numEntries * 0.7f); - // second ledger write remaining entries, which is higher than low water mark - // and less than high water mark - int num2 = numEntries - num3 - num1; - - LedgerHandle[] lhs = new LedgerHandle[3]; - for (int i = 0; i < 3; ++i) { - lhs[i] = bkc.createLedger(NUM_BOOKIES, NUM_BOOKIES, digestType, passwdBytes); - } - - for (int n = 0; n < numEntryLogs; n++) { - for (int k = 0; k < num1; k++) { - lhs[0].addEntry(msg.getBytes()); - } - for (int k = 0; k < num2; k++) { - lhs[1].addEntry(msg.getBytes()); - } - for (int k = 0; k < num3; k++) { - lhs[2].addEntry(msg.getBytes()); - } - if (changeNum) { - --num2; - ++num3; - } - } - - return lhs; - } - - private void verifyLedger(long lid, long startEntryId, long endEntryId) throws Exception { - LedgerHandle lh = bkc.openLedger(lid, digestType, passwdBytes); - Enumeration entries = lh.readEntries(startEntryId, endEntryId); - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertEquals(msg, new String(entry.getEntry())); - } - } - - @Test - public void testDisableCompaction() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - // disable compaction - // restart bookies - restartBookies(c -> { - c.setMinorCompactionThreshold(0.0f); - c.setMajorCompactionThreshold(0.0f); - return c; - }); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - - // remove ledger2 and ledger3 - // so entry log 1 and 2 would have ledger1 entries left - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - LOG.info("Finished deleting the ledgers contains most entries."); - - assertFalse(getGCThread().enableMajorCompaction); - assertFalse(getGCThread().enableMinorCompaction); - getGCThread().triggerGC().get(); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - - // after garbage collection, compaction should not be executed - assertEquals(lastMinorCompactionTime, getGCThread().lastMinorCompactionTime); - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - - // entry logs ([0,1].log) should not be compacted. - for (File ledgerDirectory : bookieLedgerDirs()) { - assertTrue("Not Found entry log file ([0,1].log that should have been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, false, 0, 1)); - } - } - - @Test - public void testForceGarbageCollectionWhenDisableCompactionConfigurationSettings() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - restartBookies(c -> { - c.setForceAllowCompaction(true); - c.setMajorCompactionThreshold(0.5f); - c.setMinorCompactionThreshold(0.2f); - c.setMajorCompactionInterval(0); - c.setMinorCompactionInterval(0); - return c; - }); - - assertFalse(getGCThread().enableMajorCompaction); - assertFalse(getGCThread().enableMinorCompaction); - assertTrue(getGCThread().isForceMajorCompactionAllow); - assertTrue(getGCThread().isForceMinorCompactionAllow); - - assertEquals(0.5f, getGCThread().majorCompactionThreshold, 0f); - assertEquals(0.2f, getGCThread().minorCompactionThreshold, 0f); - } - - @Test - public void testForceGarbageCollection() throws Exception { - testForceGarbageCollection(true); - testForceGarbageCollection(false); - } - - public void testForceGarbageCollection(boolean isForceCompactionAllowWhenDisableCompaction) throws Exception { - ServerConfiguration conf = newServerConfiguration(); - conf.setGcWaitTime(60000); - if (isForceCompactionAllowWhenDisableCompaction) { - conf.setMinorCompactionInterval(0); - conf.setMajorCompactionInterval(0); - conf.setForceAllowCompaction(true); - conf.setMajorCompactionThreshold(0.5f); - conf.setMinorCompactionThreshold(0.2f); - } else { - conf.setMinorCompactionInterval(120000); - conf.setMajorCompactionInterval(240000); - } - LedgerDirsManager dirManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - CheckpointSource cp = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - // Do nothing. - return null; - } - - @Override - public void checkpointComplete(Checkpoint checkPoint, boolean compact) - throws IOException { - // Do nothing. - } - }; - for (File journalDir : conf.getJournalDirs()) { - BookieImpl.checkDirectoryStructure(journalDir); - } - for (File dir : dirManager.getAllLedgerDirs()) { - BookieImpl.checkDirectoryStructure(dir); - } - runFunctionWithLedgerManagerFactory(conf, lmf -> { - try (LedgerManager lm = lmf.newLedgerManager()) { - InterleavedLedgerStorage storage = new InterleavedLedgerStorage(); - storage.initialize( - conf, - lm, - dirManager, - dirManager, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT); - storage.setCheckpointSource(cp); - storage.setCheckpointer(Checkpointer.NULL); - - storage.start(); - long startTime = System.currentTimeMillis(); - storage.gcThread.enableForceGC(); - storage.gcThread.triggerGC().get(); //major - storage.gcThread.triggerGC().get(); //minor - // Minor and Major compaction times should be larger than when we started - // this test. - assertTrue("Minor or major compaction did not trigger even on forcing.", - storage.gcThread.lastMajorCompactionTime > startTime - && storage.gcThread.lastMinorCompactionTime > startTime); - storage.shutdown(); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - return null; - }); - } - - @Test - public void testForceGarbageCollectionWhenDiskIsFull() throws Exception { - testForceGarbageCollectionWhenDiskIsFull(true); - testForceGarbageCollectionWhenDiskIsFull(false); - } - - public void testForceGarbageCollectionWhenDiskIsFull(boolean isForceCompactionAllowWhenDisableCompaction) - throws Exception { - - restartBookies(conf -> { - if (isForceCompactionAllowWhenDisableCompaction) { - conf.setMinorCompactionInterval(0); - conf.setMajorCompactionInterval(0); - conf.setForceAllowCompaction(true); - conf.setMajorCompactionThreshold(0.5f); - conf.setMinorCompactionThreshold(0.2f); - } else { - conf.setMinorCompactionInterval(120000); - conf.setMajorCompactionInterval(240000); - } - return conf; - }); - - getGCThread().suspendMajorGC(); - getGCThread().suspendMinorGC(); - long majorCompactionCntBeforeGC = 0; - long minorCompactionCntBeforeGC = 0; - long majorCompactionCntAfterGC = 0; - long minorCompactionCntAfterGC = 0; - - // disable forceMajor and forceMinor - majorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - getGCThread().triggerGC(true, true, true).get(); - majorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - assertEquals(majorCompactionCntBeforeGC, majorCompactionCntAfterGC); - assertEquals(minorCompactionCntBeforeGC, minorCompactionCntAfterGC); - - // enable forceMajor and forceMinor - majorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - getGCThread().triggerGC(true, false, false).get(); - majorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - assertEquals(majorCompactionCntBeforeGC + 1, majorCompactionCntAfterGC); - assertEquals(minorCompactionCntBeforeGC, minorCompactionCntAfterGC); - - // enable forceMajor and disable forceMinor - majorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - getGCThread().triggerGC(true, false, true).get(); - majorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - assertEquals(majorCompactionCntBeforeGC + 1, majorCompactionCntAfterGC); - assertEquals(minorCompactionCntBeforeGC, minorCompactionCntAfterGC); - - // disable forceMajor and enable forceMinor - majorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntBeforeGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - getGCThread().triggerGC(true, true, false).get(); - majorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMajorCompactionCounter(); - minorCompactionCntAfterGC = getGCThread().getGarbageCollectionStatus().getMinorCompactionCounter(); - assertEquals(majorCompactionCntBeforeGC, majorCompactionCntAfterGC); - assertEquals(minorCompactionCntBeforeGC + 1, minorCompactionCntAfterGC); - - } - - @Test - public void testMinorCompaction() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c -> { - // disable major compaction - c.setMajorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - return c; - }); - - - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - assertTrue( - "ACTIVE_ENTRY_LOG_COUNT should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_COUNT) - .getSample().intValue() > 0); - assertTrue( - "ACTIVE_ENTRY_LOG_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_SPACE_BYTES) - .getSample().intValue() > 0); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertTrue(getGCThread().enableMinorCompaction); - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - - // after garbage collection, major compaction should not be executed - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - - // entry logs ([0,1,2].log) should be compacted. - for (File ledgerDirectory : bookieLedgerDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even though entry log files are removed, we still can access entries for ledger1 - // since those entries have been compacted to a new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - - assertTrue( - "RECLAIMED_COMPACTION_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getCounter("bookie.gc." + RECLAIMED_COMPACTION_SPACE_BYTES) - .get().intValue() > 0); - assertTrue( - "RECLAIMED_DELETION_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getCounter("bookie.gc." + RECLAIMED_DELETION_SPACE_BYTES) - .get().intValue() > 0); - } - - @Test - public void testMinorCompactionWithMaxTimeMillisOk() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(6, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // disable major compaction - // restart bookies - restartBookies(c-> { - c.setMajorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - - // Setup limit on compaction duration. - // The limit is enough to compact. - c.setMinorCompactionMaxTimeMillis(5000); - c.setMajorCompactionMaxTimeMillis(5000); - - return c; - }); - - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - assertTrue( - "ACTIVE_ENTRY_LOG_COUNT should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_COUNT) - .getSample().intValue() > 0); - assertTrue( - "ACTIVE_ENTRY_LOG_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_SPACE_BYTES) - .getSample().intValue() > 0); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertTrue(getGCThread().enableMinorCompaction); - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - - // after garbage collection, major compaction should not be executed - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - - // entry logs ([0,1,2].log) should be compacted. - for (File ledgerDirectory : tmpDirs.getDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even though entry log files are removed, we still can access entries for ledger1 - // since those entries have been compacted to a new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - - assertTrue( - "RECLAIMED_COMPACTION_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getCounter("bookie.gc." + RECLAIMED_COMPACTION_SPACE_BYTES) - .get().intValue() > 0); - assertTrue( - "RECLAIMED_DELETION_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getCounter("bookie.gc." + RECLAIMED_DELETION_SPACE_BYTES) - .get().intValue() > 0); - } - - - @Test - public void testMinorCompactionWithMaxTimeMillisTooShort() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(6, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // disable major compaction - // restart bookies - restartBookies(c-> { - c.setMajorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - - // Setup limit on compaction duration. - // The limit is not enough to finish the compaction - c.setMinorCompactionMaxTimeMillis(1); - c.setMajorCompactionMaxTimeMillis(1); - - return c; - }); - - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - assertTrue( - "ACTIVE_ENTRY_LOG_COUNT should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_COUNT) - .getSample().intValue() > 0); - assertTrue( - "ACTIVE_ENTRY_LOG_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_SPACE_BYTES) - .getSample().intValue() > 0); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertTrue(getGCThread().enableMinorCompaction); - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - - // after garbage collection, major compaction should not be executed - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - - // entry logs ([0,1,2].log) should be compacted. - for (File ledgerDirectory : tmpDirs.getDirs()) { - // Compaction of at least one of the files should not finish up - assertTrue("Not found entry log file ([0,1,2].log that should not have been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - } - - @Test - public void testForceMinorCompaction() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c-> { - c.setMajorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(-1); - c.setMajorCompactionInterval(-1); - c.setForceAllowCompaction(true); - return c; - }); - - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - assertTrue( - "ACTIVE_ENTRY_LOG_COUNT should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_COUNT) - .getSample().intValue() > 0); - assertTrue( - "ACTIVE_ENTRY_LOG_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getGauge("bookie.gc." + ACTIVE_ENTRY_LOG_SPACE_BYTES) - .getSample().intValue() > 0); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertFalse(getGCThread().enableMinorCompaction); - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - - // after garbage collection, major compaction should not be executed - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - - // entry logs ([0,1,2].log) should be compacted. - for (File ledgerDirectory : tmpDirs.getDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even though entry log files are removed, we still can access entries for ledger1 - // since those entries have been compacted to a new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - - assertTrue( - "RECLAIMED_COMPACTION_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getCounter("bookie.gc." + RECLAIMED_COMPACTION_SPACE_BYTES) - .get().intValue() > 0); - assertTrue( - "RECLAIMED_DELETION_SPACE_BYTES should have been updated", - getStatsProvider(0) - .getCounter("bookie.gc." + RECLAIMED_DELETION_SPACE_BYTES) - .get().intValue() > 0); - } - - @Test - public void testMinorCompactionWithEntryLogPerLedgerEnabled() throws Exception { - // restart bookies - restartBookies(c-> { - c.setMajorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - c.setForceAllowCompaction(true); - c.setEntryLogPerLedgerEnabled(true); - return c; - }); - - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertTrue(getGCThread().enableMinorCompaction); - - // remove ledgers 1 and 2 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - // Need to wait until entry log 3 gets flushed before initiating GC to satisfy assertions. - while (!getGCThread().entryLogger.getFlushedLogIds().contains(3L)) { - TimeUnit.MILLISECONDS.sleep(100); - } - - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().triggerGC(true, false, false).get(); - - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - - // At this point, we have the following state of ledgers end entry logs: - // L0 (not deleted) -> E0 (un-flushed): Entry log should exist. - // L1 (deleted) -> E1 (un-flushed): Entry log should exist as un-flushed entry logs are not considered for GC. - // L2 (deleted) -> E2 (flushed): Entry log should have been garbage collected. - // E3 (flushed): Entry log should have been garbage collected. - // E4 (un-flushed): Entry log should exist as un-flushed entry logs are not considered for GC. - assertTrue("Not found entry log files [0, 1, 4].log that should not have been compacted in: " - + tmpDirs.getDirs().get(0), TestUtils.hasAllLogFiles(tmpDirs.getDirs().get(0), 0, 1, 4)); - assertTrue("Found entry log files [2, 3].log that should have been compacted in ledgerDirectory: " - + tmpDirs.getDirs().get(0), TestUtils.hasNoneLogFiles(tmpDirs.getDirs().get(0), 2, 3)); - - // Now, let's mark E1 as flushed, as its ledger L1 has been deleted already. In this case, the GC algorithm - // should consider it for deletion. - ((DefaultEntryLogger) getGCThread().entryLogger).recentlyCreatedEntryLogsStatus.flushRotatedEntryLog(1L); - getGCThread().triggerGC(true, false, false).get(); - assertTrue("Found entry log file 1.log that should have been compacted in ledgerDirectory: " - + tmpDirs.getDirs().get(0), TestUtils.hasNoneLogFiles(tmpDirs.getDirs().get(0), 1)); - - // Once removed the ledger L0, then deleting E0 is fine (only if it has been flushed). - bkc.deleteLedger(lhs[0].getId()); - getGCThread().triggerGC(true, false, false).get(); - assertTrue("Found entry log file 0.log that should not have been compacted in ledgerDirectory: " - + tmpDirs.getDirs().get(0), TestUtils.hasAllLogFiles(tmpDirs.getDirs().get(0), 0)); - ((DefaultEntryLogger) getGCThread().entryLogger).recentlyCreatedEntryLogsStatus.flushRotatedEntryLog(0L); - getGCThread().triggerGC(true, false, false).get(); - assertTrue("Found entry log file 0.log that should have been compacted in ledgerDirectory: " - + tmpDirs.getDirs().get(0), TestUtils.hasNoneLogFiles(tmpDirs.getDirs().get(0), 0)); - } - - @Test - public void testMinorCompactionWithNoWritableLedgerDirs() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c -> { - // disable major compaction - c.setMajorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - return c; - }); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertTrue(getGCThread().enableMinorCompaction); - - for (int i = 0; i < bookieCount(); i++) { - BookieImpl bookie = ((BookieImpl) serverByIndex(i).getBookie()); - LedgerDirsManager ledgerDirsManager = bookie.getLedgerDirsManager(); - List ledgerDirs = ledgerDirsManager.getAllLedgerDirs(); - // if all the discs are full then Major and Minor compaction would be disabled since - // 'isForceGCAllowWhenNoSpace' is not enabled. Check LedgerDirsListener of interleavedLedgerStorage. - for (File ledgerDir : ledgerDirs) { - ledgerDirsManager.addToFilledDirs(ledgerDir); - } - } - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().triggerGC().get(); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - // after garbage collection, major compaction should not be executed - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - assertEquals(lastMinorCompactionTime, getGCThread().lastMinorCompactionTime); - - // entry logs ([0,1,2].log) should still remain, because both major and Minor compaction are disabled. - for (File ledgerDirectory : bookieLedgerDirs()) { - assertTrue( - "All the entry log files ([0,1,2].log are not available, which is not expected" + ledgerDirectory, - TestUtils.hasLogFiles(ledgerDirectory, false, 0, 1, 2)); - } - } - - @Test - public void testMinorCompactionWithNoWritableLedgerDirsButIsForceGCAllowWhenNoSpaceIsSet() throws Exception { - stopAllBookies(); - ServerConfiguration conf = newServerConfiguration(); - // disable major compaction - conf.setMajorCompactionThreshold(0.0f); - // here we are setting isForceGCAllowWhenNoSpace to true, so Major and Minor compaction wont be disabled in case - // when discs are full - conf.setIsForceGCAllowWhenNoSpace(true); - conf.setGcWaitTime(600000); - conf.setMinorCompactionInterval(120000); - conf.setMajorCompactionInterval(240000); - // We need at least 2 ledger dirs because compaction will flush ledger cache, and will - // trigger relocateIndexFileAndFlushHeader. If we only have one ledger dir, compaction will always fail - // when there's no writeable ledger dir. - File ledgerDir1 = tmpDirs.createNew("ledger", "test1"); - File ledgerDir2 = tmpDirs.createNew("ledger", "test2"); - File journalDir = tmpDirs.createNew("journal", "test"); - String[] ledgerDirNames = new String[]{ - ledgerDir1.getPath(), - ledgerDir2.getPath() - }; - conf.setLedgerDirNames(ledgerDirNames); - conf.setJournalDirName(journalDir.getPath()); - BookieServer server = startAndAddBookie(conf).getServer(); - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertTrue(getGCThread().enableMinorCompaction); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - for (int i = 0; i < bookieCount(); i++) { - BookieImpl bookie = ((BookieImpl) serverByIndex(i).getBookie()); - bookie.getLedgerStorage().flush(); - bookie.dirsMonitor.shutdown(); - LedgerDirsManager ledgerDirsManager = bookie.getLedgerDirsManager(); - List ledgerDirs = ledgerDirsManager.getAllLedgerDirs(); - // Major and Minor compaction are not disabled even though discs are full. Check LedgerDirsListener of - // interleavedLedgerStorage. - for (File ledgerDir : ledgerDirs) { - ledgerDirsManager.addToFilledDirs(ledgerDir); - } - } - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().triggerGC(true, false, false).get(); - - // after garbage collection, major compaction should not be executed - assertEquals(lastMajorCompactionTime, getGCThread().lastMajorCompactionTime); - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - - // though all discs are added to filled dirs list, compaction would succeed, because in EntryLogger for - // allocating newlog - // we get getWritableLedgerDirsForNewLog() of ledgerDirsManager instead of getWritableLedgerDirs() - // entry logs ([0,1,2].log) should be compacted. - for (File ledgerDirectory : ((BookieImpl) server.getBookie()).getLedgerDirsManager().getAllLedgerDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory.getParentFile(), true, 0, 1, 2)); - } - - // even entry log files are removed, we still can access entries for ledger1 - // since those entries has been compacted to new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - - // for the sake of validity of test lets make sure that there is no writableLedgerDir in the bookies - for (int i = 0; i < bookieCount(); i++) { - BookieImpl bookie = (BookieImpl) serverByIndex(i).getBookie(); - LedgerDirsManager ledgerDirsManager = bookie.getLedgerDirsManager(); - try { - List ledgerDirs = ledgerDirsManager.getWritableLedgerDirs(); - // it is expected not to have any writableLedgerDirs since we added all of them to FilledDirs - fail("It is expected not to have any writableLedgerDirs"); - } catch (NoWritableLedgerDirException nwe) { - - } - } - } - - @Test - public void testMajorCompaction() throws Exception { - - // prepare data - LedgerHandle[] lhs = prepareData(3, true); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c -> { - // disable minor compaction - c.setMinorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - return c; - }); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertTrue(getGCThread().enableMajorCompaction); - assertFalse(getGCThread().enableMinorCompaction); - - // remove ledger1 and ledger3 - bkc.deleteLedger(lhs[0].getId()); - bkc.deleteLedger(lhs[2].getId()); - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - // after garbage collection, minor compaction should not be executed - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - assertTrue(getGCThread().lastMajorCompactionTime > lastMajorCompactionTime); - - // entry logs ([0,1,2].log) should be compacted - for (File ledgerDirectory : bookieLedgerDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even entry log files are removed, we still can access entries for ledger2 - // since those entries has been compacted to new entry log - verifyLedger(lhs[1].getId(), 0, lhs[1].getLastAddConfirmed()); - } - - @Test - public void testForceMajorCompaction() throws Exception { - - // prepare data - LedgerHandle[] lhs = prepareData(3, true); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c-> { - // disable minor compaction - c.setMinorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(-1); - c.setMajorCompactionInterval(-1); - c.setForceAllowCompaction(true); - return c; - }); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertFalse(getGCThread().enableMajorCompaction); - assertFalse(getGCThread().enableMinorCompaction); - assertTrue(getGCThread().isForceMajorCompactionAllow); - assertFalse(getGCThread().isForceMinorCompactionAllow); - - // remove ledger1 and ledger3 - bkc.deleteLedger(lhs[0].getId()); - bkc.deleteLedger(lhs[2].getId()); - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - // after garbage collection, minor compaction should not be executed - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - assertTrue(getGCThread().lastMajorCompactionTime > lastMajorCompactionTime); - - // entry logs ([0,1,2].log) should be compacted - for (File ledgerDirectory : tmpDirs.getDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even entry log files are removed, we still can access entries for ledger2 - // since those entries has been compacted to new entry log - verifyLedger(lhs[1].getId(), 0, lhs[1].getLastAddConfirmed()); - } - - @Test - public void testCompactionPersistence() throws Exception { - /* - * for this test scenario we are assuming that there will be only one - * bookie in the cluster - */ - assertEquals("Numbers of Bookies in this cluster", 1, numBookies); - /* - * this test is for validating EntryLogCompactor, so make sure - * TransactionalCompaction is not enabled. - */ - assertFalse("Bookies must be using EntryLogCompactor", baseConf.getUseTransactionalCompaction()); - // prepare data - LedgerHandle[] lhs = prepareData(3, true); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c -> { - // disable minor compaction - c.setMinorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - return c; - }); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertTrue(getGCThread().enableMajorCompaction); - assertFalse(getGCThread().enableMinorCompaction); - - // remove ledger1 and ledger3 - bkc.deleteLedger(lhs[0].getId()); - bkc.deleteLedger(lhs[2].getId()); - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - - // after garbage collection, minor compaction should not be executed - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - assertTrue(getGCThread().lastMajorCompactionTime > lastMajorCompactionTime); - - // entry logs ([0,1,2].log) should be compacted - for (File ledgerDirectory : bookieLedgerDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even entry log files are removed, we still can access entries for - // ledger2 - // since those entries has been compacted to new entry log - long ledgerId = lhs[1].getId(); - long lastAddConfirmed = lhs[1].getLastAddConfirmed(); - verifyLedger(ledgerId, 0, lastAddConfirmed); - - /* - * there is only one bookie in the cluster so we should be able to read - * entries from this bookie. - */ - ServerConfiguration bookieServerConfig = ((BookieImpl) serverByIndex(0).getBookie()).conf; - ServerConfiguration newBookieConf = new ServerConfiguration(bookieServerConfig); - /* - * by reusing bookieServerConfig and setting metadataServiceUri to null - * we can create/start new Bookie instance using the same data - * (journal/ledger/index) of the existing BookeieServer for our testing - * purpose. - */ - newBookieConf.setMetadataServiceUri(null); - String entryLogCachePath = tmpDirs.createNew("entry", "bk2").getAbsolutePath(); - newBookieConf.setGcEntryLogMetadataCachePath(entryLogCachePath); - Bookie newbookie = new TestBookieImpl(newBookieConf); - - DigestManager digestManager = DigestManager.instantiate(ledgerId, passwdBytes, - BookKeeper.DigestType.toProtoDigestType(digestType), UnpooledByteBufAllocator.DEFAULT, - baseClientConf.getUseV2WireProtocol()); - - for (long entryId = 0; entryId <= lastAddConfirmed; entryId++) { - ByteBuf readEntryBufWithChecksum = newbookie.readEntry(ledgerId, entryId); - ByteBuf readEntryBuf = digestManager.verifyDigestAndReturnData(entryId, readEntryBufWithChecksum); - byte[] readEntryBytes = new byte[readEntryBuf.readableBytes()]; - readEntryBuf.readBytes(readEntryBytes); - assertEquals(msg, new String(readEntryBytes)); - } - } - - @Test - public void testCompactionWhenLedgerDirsAreFull() throws Exception { - /* - * for this test scenario we are assuming that there will be only one - * bookie in the cluster - */ - assertEquals("Numbers of Bookies in this cluster", 1, bookieCount()); - ServerConfiguration serverConfig = confByIndex(0); - File ledgerDir = serverConfig.getLedgerDirs()[0]; - assertEquals("Number of Ledgerdirs for this bookie", 1, serverConfig.getLedgerDirs().length); - assertTrue("indexdirs should be configured to null", null == serverConfig.getIndexDirs()); - /* - * this test is for validating EntryLogCompactor, so make sure - * TransactionalCompaction is not enabled. - */ - assertFalse("Bookies must be using EntryLogCompactor", baseConf.getUseTransactionalCompaction()); - // prepare data - LedgerHandle[] lhs = prepareData(3, true); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - serverByIndex(0).getBookie().getLedgerStorage().flush(); - assertTrue( - "entry log file ([0,1,2].log should be available in ledgerDirectory: " - + serverConfig.getLedgerDirs()[0], - TestUtils.hasLogFiles(serverConfig.getLedgerDirs()[0], false, 0, 1, 2)); - - long usableSpace = ledgerDir.getUsableSpace(); - long totalSpace = ledgerDir.getTotalSpace(); - - /* - * because of the value set for diskUsageThreshold, when bookie is - * restarted it wouldn't find any writableledgerdir. But we have set - * very low values for minUsableSizeForEntryLogCreation and - * minUsableSizeForIndexFileCreation, so it should be able to create - * EntryLog file and Index file for doing compaction. - */ - - // restart bookies - restartBookies(c -> { - c.setForceReadOnlyBookie(true); - c.setIsForceGCAllowWhenNoSpace(true); - // disable minor compaction - c.setMinorCompactionThreshold(0.0f); - c.setGcWaitTime(60000); - c.setMinorCompactionInterval(120000); - c.setMajorCompactionInterval(240000); - c.setMinUsableSizeForEntryLogCreation(1); - c.setMinUsableSizeForIndexFileCreation(1); - c.setDiskUsageThreshold((1.0f - ((float) usableSpace / (float) totalSpace)) * 0.9f); - c.setDiskUsageWarnThreshold(0.0f); - return c; - }); - - assertFalse("There shouldn't be any writable ledgerDir", - ((BookieImpl) serverByIndex(0).getBookie()).getLedgerDirsManager().hasWritableLedgerDirs()); - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertTrue(getGCThread().enableMajorCompaction); - assertFalse(getGCThread().enableMinorCompaction); - - // remove ledger1 and ledger3 - bkc.deleteLedger(lhs[0].getId()); - bkc.deleteLedger(lhs[2].getId()); - LOG.info("Finished deleting the ledgers contains most entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - // after garbage collection, minor compaction should not be executed - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - assertTrue(getGCThread().lastMajorCompactionTime > lastMajorCompactionTime); - - /* - * GarbageCollection should have succeeded, so no previous entrylog - * should be available. - */ - - // entry logs ([0,1,2].log) should be compacted - for (File ledgerDirectory : bookieLedgerDirs()) { - assertFalse("Found entry log file ([0,1,2].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even entry log files are removed, we still can access entries for - // ledger2 - // since those entries has been compacted to new entry log - long ledgerId = lhs[1].getId(); - long lastAddConfirmed = lhs[1].getLastAddConfirmed(); - verifyLedger(ledgerId, 0, lastAddConfirmed); - } - - @Test - public void testMajorCompactionAboveThreshold() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - long lastMinorCompactionTime = getGCThread().lastMinorCompactionTime; - long lastMajorCompactionTime = getGCThread().lastMajorCompactionTime; - assertTrue(getGCThread().enableMajorCompaction); - assertTrue(getGCThread().enableMinorCompaction); - - // remove ledger1 and ledger2 - bkc.deleteLedger(lhs[0].getId()); - bkc.deleteLedger(lhs[1].getId()); - LOG.info("Finished deleting the ledgers contains less entries."); - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - - // after garbage collection, minor compaction should not be executed - assertTrue(getGCThread().lastMinorCompactionTime > lastMinorCompactionTime); - assertTrue(getGCThread().lastMajorCompactionTime > lastMajorCompactionTime); - - // entry logs ([0,1,2].log) should not be compacted - for (File ledgerDirectory : bookieLedgerDirs()) { - assertTrue("Not Found entry log file ([1,2].log that should have been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, false, 0, 1, 2)); - } - } - - @Test - public void testCompactionSmallEntryLogs() throws Exception { - - // create a ledger to write a few entries - LedgerHandle alh = bkc.createLedger(NUM_BOOKIES, NUM_BOOKIES, digestType, "".getBytes()); - for (int i = 0; i < 3; i++) { - alh.addEntry(msg.getBytes()); - } - alh.close(); - - // restart bookie to roll entry log files - restartBookies(); - - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - LOG.info("Finished deleting the ledgers contains most entries."); - // restart bookies again to roll entry log files. - restartBookies(); - - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - if (useMetadataCache) { - assertTrue(getGCThread().getEntryLogMetaMap() instanceof PersistentEntryLogMetadataMap); - } - // entry logs (0.log) should not be compacted - // entry logs ([1,2,3].log) should be compacted. - for (File ledgerDirectory : bookieLedgerDirs()) { - assertTrue("Not Found entry log file ([0].log that should have been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0)); - assertFalse("Found entry log file ([1,2,3].log that should have not been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 1, 2, 3)); - } - - // even entry log files are removed, we still can access entries for ledger1 - // since those entries has been compacted to new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - } - - /** - * Test that compaction doesnt add to index without having persisted - * entrylog first. This is needed because compaction doesn't go through the journal. - * {@see https://issues.apache.org/jira/browse/BOOKKEEPER-530} - * {@see https://issues.apache.org/jira/browse/BOOKKEEPER-664} - */ - @Test - public void testCompactionSafety() throws Exception { - tearDown(); // I dont want the test infrastructure - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - final Set ledgers = Collections.newSetFromMap(new ConcurrentHashMap()); - LedgerManager manager = getLedgerManager(ledgers); - - File tmpDir = tmpDirs.createNew("bkTest", ".dir"); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - conf.setLedgerDirNames(new String[] {tmpDir.toString()}); - - conf.setEntryLogSizeLimit(DefaultEntryLogger.LOGFILE_HEADER_SIZE + 3 * (4 + ENTRY_SIZE)); - conf.setGcWaitTime(100); - conf.setMinorCompactionThreshold(0.7f); - conf.setMajorCompactionThreshold(0.0f); - conf.setMinorCompactionInterval(1); - conf.setMajorCompactionInterval(10); - conf.setPageLimit(1); - - CheckpointSource checkpointSource = new CheckpointSource() { - AtomicInteger idGen = new AtomicInteger(0); - class MyCheckpoint implements CheckpointSource.Checkpoint { - int id = idGen.incrementAndGet(); - @Override - public int compareTo(CheckpointSource.Checkpoint o) { - if (o == CheckpointSource.Checkpoint.MAX) { - return -1; - } else if (o == CheckpointSource.Checkpoint.MIN) { - return 1; - } - return id - ((MyCheckpoint) o).id; - } - } - - @Override - public CheckpointSource.Checkpoint newCheckpoint() { - return new MyCheckpoint(); - } - - public void checkpointComplete(CheckpointSource.Checkpoint checkpoint, boolean compact) - throws IOException { - } - }; - final byte[] key = "foobar".getBytes(); - File log0 = new File(curDir, "0.log"); - LedgerDirsManager dirs = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - assertFalse("Log shouldnt exist", log0.exists()); - InterleavedLedgerStorage storage = new InterleavedLedgerStorage(); - storage.initialize( - conf, - manager, - dirs, - dirs, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT); - storage.setCheckpointSource(checkpointSource); - storage.setCheckpointer(Checkpointer.NULL); - - ledgers.add(1L); - ledgers.add(2L); - ledgers.add(3L); - storage.setMasterKey(1, key); - storage.setMasterKey(2, key); - storage.setMasterKey(3, key); - storage.addEntry(genEntry(1, 1, ENTRY_SIZE)); - storage.addEntry(genEntry(2, 1, ENTRY_SIZE)); - storage.addEntry(genEntry(2, 2, ENTRY_SIZE)); - storage.addEntry(genEntry(3, 2, ENTRY_SIZE)); - storage.flush(); - storage.shutdown(); - - assertTrue("Log should exist", log0.exists()); - ledgers.remove(2L); - ledgers.remove(3L); - - storage = new InterleavedLedgerStorage(); - storage.initialize( - conf, - manager, - dirs, dirs, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT); - storage.setCheckpointSource(checkpointSource); - storage.setCheckpointer(Checkpointer.NULL); - - storage.start(); - for (int i = 0; i < 10; i++) { - if (!log0.exists()) { - break; - } - Thread.sleep(1000); - storage.entryLogger.flush(); // simulate sync thread - } - assertFalse("Log shouldnt exist", log0.exists()); - - ledgers.add(4L); - storage.setMasterKey(4, key); - storage.addEntry(genEntry(4, 1, ENTRY_SIZE)); // force ledger 1 page to flush - storage.shutdown(); - - storage = new InterleavedLedgerStorage(); - storage.initialize( - conf, - manager, - dirs, - dirs, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT); - storage.setCheckpointSource(checkpointSource); - storage.setCheckpointer(Checkpointer.NULL); - - storage.getEntry(1, 1); // entry should exist - } - - @Test - public void testCancelledCompactionWhenShuttingDown() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - // change compaction in low throughput - // restart bookies - restartBookies(c -> { - c.setIsThrottleByBytes(true); - c.setCompactionRateByBytes(ENTRY_SIZE / 1000); - c.setMinorCompactionThreshold(0.2f); - c.setMajorCompactionThreshold(0.5f); - return c; - }); - - // remove ledger2 and ledger3 - // so entry log 1 and 2 would have ledger1 entries left - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - LOG.info("Finished deleting the ledgers contains most entries."); - - getGCThread().triggerGC(true, false, false); - getGCThread().throttler.cancelledAcquire(); - waitUntilTrue(() -> { - try { - return getGCThread().compacting.get(); - } catch (Exception e) { - fail("Get GC thread failed"); - } - return null; - }, () -> "Not attempting to complete", 10000, 200); - - getGCThread().shutdown(); - // after garbage collection shutdown, compaction should be cancelled when acquire permits - // and GC running flag should be false. - assertFalse(getGCThread().running); - - } - - private void waitUntilTrue(Supplier condition, - Supplier msg, - long waitTime, - long pause) throws InterruptedException { - long startTime = System.currentTimeMillis(); - while (true) { - if (condition.get()) { - return; - } - if (System.currentTimeMillis() > startTime + waitTime) { - fail(msg.get()); - } - Thread.sleep(Math.min(waitTime, pause)); - } - } - - private LedgerManager getLedgerManager(final Set ledgers) { - LedgerManager manager = new LedgerManager() { - @Override - public CompletableFuture> createLedgerMetadata(long lid, - LedgerMetadata metadata) { - unsupported(); - return null; - } - @Override - public CompletableFuture removeLedgerMetadata(long ledgerId, Version version) { - unsupported(); - return null; - } - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - unsupported(); - return null; - } - @Override - public CompletableFuture> writeLedgerMetadata(long ledgerId, - LedgerMetadata metadata, - Version currentVersion) { - unsupported(); - return null; - } - @Override - public void asyncProcessLedgers(Processor processor, - AsyncCallback.VoidCallback finalCb, - Object context, int successRc, int failureRc) { - unsupported(); - } - @Override - public void registerLedgerMetadataListener(long ledgerId, - LedgerMetadataListener listener) { - unsupported(); - } - @Override - public void unregisterLedgerMetadataListener(long ledgerId, - LedgerMetadataListener listener) { - unsupported(); - } - @Override - public void close() throws IOException {} - - void unsupported() { - LOG.error("Unsupported operation called", new Exception()); - throw new RuntimeException("Unsupported op"); - } - - @Override - public LedgerRangeIterator getLedgerRanges(long zkOpTimeoutMs) { - final AtomicBoolean hasnext = new AtomicBoolean(true); - return new LedgerManager.LedgerRangeIterator() { - @Override - public boolean hasNext() throws IOException { - return hasnext.get(); - } - @Override - public LedgerManager.LedgerRange next() throws IOException { - hasnext.set(false); - return new LedgerManager.LedgerRange(ledgers); - } - }; - } - }; - return manager; - } - - /** - * Test that compaction should execute silently when there is no entry logs - * to compact. {@see https://issues.apache.org/jira/browse/BOOKKEEPER-700} - */ - @Test - public void testWhenNoLogsToCompact() throws Exception { - tearDown(); // I dont want the test infrastructure - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - File tmpDir = tmpDirs.createNew("bkTest", ".dir"); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - - LedgerDirsManager dirs = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - final Set ledgers = Collections - .newSetFromMap(new ConcurrentHashMap()); - LedgerManager manager = getLedgerManager(ledgers); - CheckpointSource checkpointSource = new CheckpointSource() { - - @Override - public Checkpoint newCheckpoint() { - return null; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, - boolean compact) throws IOException { - } - }; - InterleavedLedgerStorage storage = new InterleavedLedgerStorage(); - storage.initialize( - conf, - manager, - dirs, - dirs, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT); - storage.setCheckpointSource(checkpointSource); - storage.setCheckpointer(Checkpointer.NULL); - - double threshold = 0.1; - long limit = 0; - - // shouldn't throw exception - storage.gcThread.doCompactEntryLogs(threshold, limit); - } - - private ByteBuf genEntry(long ledger, long entry, int size) { - ByteBuf bb = Unpooled.buffer(size); - bb.writeLong(ledger); - bb.writeLong(entry); - while (bb.isWritable()) { - bb.writeByte((byte) 0xFF); - } - return bb; - } - - /** - * Suspend garbage collection when suspendMajor/suspendMinor is set. - */ - @Test - public void testSuspendGarbageCollection() throws Exception { - ServerConfiguration conf = newServerConfiguration(); - conf.setGcWaitTime(500); - conf.setMinorCompactionInterval(1); - conf.setMajorCompactionInterval(2); - conf.setMajorCompactionMaxTimeMillis(5000); - runFunctionWithLedgerManagerFactory(conf, lmf -> { - try (LedgerManager lm = lmf.newLedgerManager()) { - testSuspendGarbageCollection(conf, lm); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - return null; - }); - } - - private void testSuspendGarbageCollection(ServerConfiguration conf, - LedgerManager lm) throws Exception { - LedgerDirsManager dirManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - CheckpointSource cp = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - // Do nothing. - return null; - } - - @Override - public void checkpointComplete(Checkpoint checkPoint, boolean compact) - throws IOException { - // Do nothing. - } - }; - for (File journalDir : conf.getJournalDirs()) { - BookieImpl.checkDirectoryStructure(journalDir); - } - for (File dir : dirManager.getAllLedgerDirs()) { - BookieImpl.checkDirectoryStructure(dir); - } - InterleavedLedgerStorage storage = new InterleavedLedgerStorage(); - TestStatsProvider stats = new TestStatsProvider(); - storage.initialize( - conf, - lm, - dirManager, - dirManager, - stats.getStatsLogger("storage"), - UnpooledByteBufAllocator.DEFAULT); - storage.setCheckpointSource(cp); - storage.setCheckpointer(Checkpointer.NULL); - - storage.start(); - - int majorCompactions = stats.getCounter("storage.gc." + MAJOR_COMPACTION_COUNT).get().intValue(); - int minorCompactions = stats.getCounter("storage.gc." + MINOR_COMPACTION_COUNT).get().intValue(); - Thread.sleep(3 * (conf.getMajorCompactionInterval() * 1000 - + conf.getGcWaitTime() - + conf.getMajorCompactionMaxTimeMillis())); - assertTrue( - "Major compaction should have happened", - stats.getCounter("storage.gc." + MAJOR_COMPACTION_COUNT).get() > majorCompactions); - - // test suspend Major GC. - storage.gcThread.suspendMajorGC(); - - Thread.sleep(1000); - long startTime = System.currentTimeMillis(); - majorCompactions = stats.getCounter("storage.gc." + MAJOR_COMPACTION_COUNT).get().intValue(); - Thread.sleep(conf.getMajorCompactionInterval() * 1000 - + conf.getGcWaitTime()); - assertTrue("major compaction triggered while suspended", - storage.gcThread.lastMajorCompactionTime < startTime); - assertTrue("major compaction triggered while suspended", - stats.getCounter("storage.gc." + MAJOR_COMPACTION_COUNT).get() == majorCompactions); - - // test suspend Major GC. - Thread.sleep(conf.getMinorCompactionInterval() * 1000 - + conf.getGcWaitTime()); - assertTrue( - "Minor compaction should have happened", - stats.getCounter("storage.gc." + MINOR_COMPACTION_COUNT).get() > minorCompactions); - - // test suspend Minor GC. - storage.gcThread.suspendMinorGC(); - - Thread.sleep(1000); - startTime = System.currentTimeMillis(); - minorCompactions = stats.getCounter("storage.gc." + MINOR_COMPACTION_COUNT).get().intValue(); - Thread.sleep(conf.getMajorCompactionInterval() * 1000 - + conf.getGcWaitTime()); - assertTrue("minor compaction triggered while suspended", - storage.gcThread.lastMinorCompactionTime < startTime); - assertTrue("minor compaction triggered while suspended", - stats.getCounter("storage.gc." + MINOR_COMPACTION_COUNT).get() == minorCompactions); - - // test resume - storage.gcThread.resumeMinorGC(); - storage.gcThread.resumeMajorGC(); - - Thread.sleep((conf.getMajorCompactionInterval() + conf.getMinorCompactionInterval()) * 1000 - + (conf.getGcWaitTime() * 2)); - assertTrue( - "Major compaction should have happened", - stats.getCounter("storage.gc." + MAJOR_COMPACTION_COUNT).get() > majorCompactions); - assertTrue( - "Minor compaction should have happened", - stats.getCounter("storage.gc." + MINOR_COMPACTION_COUNT).get() > minorCompactions); - assertTrue( - "gcThreadRunttime should be non-zero", - stats.getOpStatsLogger("storage.gc." + THREAD_RUNTIME).getSuccessCount() > 0); - - } - - @Test - public void testRecoverIndexWhenIndexIsPartiallyFlush() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(3, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c -> { - // disable compaction - c.setMinorCompactionThreshold(0.0f); - c.setMajorCompactionThreshold(0.0f); - c.setGcWaitTime(600000); - return c; - }); - - - - BookieImpl bookie = ((BookieImpl) serverByIndex(0).getBookie()); - InterleavedLedgerStorage storage = (InterleavedLedgerStorage) bookie.ledgerStorage; - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - - MockTransactionalEntryLogCompactor partialCompactionWorker = new MockTransactionalEntryLogCompactor( - ((InterleavedLedgerStorage) bookie.getLedgerStorage()).gcThread); - - for (long logId = 0; logId < 3; logId++) { - EntryLogMetadata meta = storage.entryLogger.getEntryLogMetadata(logId); - partialCompactionWorker.compactWithIndexFlushFailure(meta); - } - - // entry logs ([0,1,2].log) should not be compacted because of partial flush throw IOException - for (File ledgerDirectory : bookieLedgerDirs()) { - assertTrue("Entry log file ([0,1,2].log should not be compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // entries should be available - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - - // But we should see .compacted file with index flush failure - assertEquals(findCompactedEntryLogFiles().size(), 3); - - // Now try to recover those flush failed index files - partialCompactionWorker.cleanUpAndRecover(); - - // There should be no .compacted files after recovery - assertEquals(findCompactedEntryLogFiles().size(), 0); - - // compaction worker should recover partial flushed index and delete [0,1,2].log - for (File ledgerDirectory : bookieLedgerDirs()) { - assertFalse("Entry log file ([0,1,2].log should have been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2)); - } - - // even entry log files are removed, we still can access entries for ledger1 - // since those entries has been compacted to new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - } - - @Test - public void testCompactionFailureShouldNotResultInDuplicatedData() throws Exception { - // prepare data - LedgerHandle[] lhs = prepareData(5, false); - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - // restart bookies - restartBookies(c -> { - // disable compaction - c.setMinorCompactionThreshold(0.0f); - c.setMajorCompactionThreshold(0.0f); - c.setUseTransactionalCompaction(true); - return c; - }); - - // remove ledger2 and ledger3 - bkc.deleteLedger(lhs[1].getId()); - bkc.deleteLedger(lhs[2].getId()); - - LOG.info("Finished deleting the ledgers contains most entries."); - Thread.sleep(baseConf.getMajorCompactionInterval() * 1000 - + baseConf.getGcWaitTime()); - BookieImpl bookie = (BookieImpl) serverByIndex(0).getBookie(); - InterleavedLedgerStorage storage = (InterleavedLedgerStorage) bookie.ledgerStorage; - - List ledgerDirs = bookie.getLedgerDirsManager().getAllLedgerDirs(); - List usageBeforeCompaction = new ArrayList<>(); - ledgerDirs.forEach(file -> usageBeforeCompaction.add(getDirectorySpaceUsage(file))); - - MockTransactionalEntryLogCompactor partialCompactionWorker = new MockTransactionalEntryLogCompactor( - ((InterleavedLedgerStorage) bookie.ledgerStorage).gcThread); - - for (long logId = 0; logId < 5; logId++) { - EntryLogMetadata meta = storage.entryLogger.getEntryLogMetadata(logId); - partialCompactionWorker.compactWithLogFlushFailure(meta); - } - - // entry logs ([0-4].log) should not be compacted because of failure in flush compaction log - for (File ledgerDirectory : bookieLedgerDirs()) { - assertTrue("Entry log file ([0,1,2].log should not be compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2, 3, 4)); - } - // even entry log files are removed, we still can access entries for ledger1 - // since those entries has been compacted to new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - - List freeSpaceAfterCompactionFailed = new ArrayList<>(); - ledgerDirs.forEach(file -> freeSpaceAfterCompactionFailed.add(getDirectorySpaceUsage(file))); - - // No extra data is generated after compaction fail - for (int i = 0; i < usageBeforeCompaction.size(); i++) { - assertEquals(usageBeforeCompaction.get(i), freeSpaceAfterCompactionFailed.get(i)); - } - - - // restart bookies - restartBookies(c -> { - // now enable normal compaction - c.setMajorCompactionThreshold(0.5f); - c.setMajorCompactionMaxTimeMillis(5000); - return c; - }); - - getGCThread().enableForceGC(); - getGCThread().triggerGC().get(); - - Thread.sleep(confByIndex(0).getMajorCompactionInterval() * 1000 - + confByIndex(0).getGcWaitTime() - + confByIndex(0).getMajorCompactionMaxTimeMillis()); - // compaction worker should compact [0-4].log - for (File ledgerDirectory : bookieLedgerDirs()) { - assertFalse("Entry log file ([0,1,2].log should have been compacted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1, 2, 3, 4)); - } - - // even entry log files are removed, we still can access entries for ledger1 - // since those entries has been compacted to new entry log - verifyLedger(lhs[0].getId(), 0, lhs[0].getLastAddConfirmed()); - } - - private long getDirectorySpaceUsage(File dir) { - long size = 0; - for (File file : dir.listFiles()) { - size += file.length(); - } - return size; - } - - private Set findCompactedEntryLogFiles() throws Exception { - Set compactedLogFiles = new HashSet<>(); - for (File ledgerDirectory : bookieLedgerDirs()) { - File[] files = BookieImpl.getCurrentDirectory(ledgerDirectory).listFiles( - file -> file.getName().endsWith(COMPACTED_SUFFIX)); - if (files != null) { - Collections.addAll(compactedLogFiles, files); - } - } - return compactedLogFiles; - } - - private static class MockTransactionalEntryLogCompactor extends TransactionalEntryLogCompactor { - - public MockTransactionalEntryLogCompactor(GarbageCollectorThread gcThread) { - super(gcThread.conf, - gcThread.entryLogger, - gcThread.ledgerStorage, - (long entry) -> { - try { - gcThread.removeEntryLog(entry); - } catch (EntryLogMetadataMapException e) { - LOG.warn("Failed to remove entry-log metadata {}", entry, e); - } - }); - } - - synchronized void compactWithIndexFlushFailure(EntryLogMetadata metadata) throws IOException { - LOG.info("Compacting entry log {}.", metadata.getEntryLogId()); - CompactionEntryLog compactionLog = entryLogger.newCompactionLog(metadata.getEntryLogId()); - - CompactionPhase scanEntryLog = new ScanEntryLogPhase(metadata, compactionLog); - if (!scanEntryLog.run()) { - LOG.info("Compaction for {} end in ScanEntryLogPhase.", metadata.getEntryLogId()); - return; - } - CompactionPhase flushCompactionLog = new FlushCompactionLogPhase(compactionLog); - if (!flushCompactionLog.run()) { - LOG.info("Compaction for {} end in FlushCompactionLogPhase.", metadata.getEntryLogId()); - return; - } - CompactionPhase partialFlushIndexPhase = new PartialFlushIndexPhase(compactionLog); - if (!partialFlushIndexPhase.run()) { - LOG.info("Compaction for {} end in PartialFlushIndexPhase.", metadata.getEntryLogId()); - return; - } - logRemovalListener.removeEntryLog(metadata.getEntryLogId()); - LOG.info("Compacted entry log : {}.", metadata.getEntryLogId()); - } - - synchronized void compactWithLogFlushFailure(EntryLogMetadata metadata) throws IOException { - LOG.info("Compacting entry log {}", metadata.getEntryLogId()); - CompactionEntryLog compactionLog = entryLogger.newCompactionLog(metadata.getEntryLogId()); - - CompactionPhase scanEntryLog = new ScanEntryLogPhase(metadata, compactionLog); - if (!scanEntryLog.run()) { - LOG.info("Compaction for {} end in ScanEntryLogPhase.", metadata.getEntryLogId()); - return; - } - CompactionPhase logFlushFailurePhase = new LogFlushFailurePhase(compactionLog); - if (!logFlushFailurePhase.run()) { - LOG.info("Compaction for {} end in FlushCompactionLogPhase.", metadata.getEntryLogId()); - return; - } - CompactionPhase updateIndex = new UpdateIndexPhase(compactionLog); - if (!updateIndex.run()) { - LOG.info("Compaction for entry log {} end in UpdateIndexPhase.", metadata.getEntryLogId()); - return; - } - logRemovalListener.removeEntryLog(metadata.getEntryLogId()); - LOG.info("Compacted entry log : {}.", metadata.getEntryLogId()); - } - - private class PartialFlushIndexPhase extends UpdateIndexPhase { - - public PartialFlushIndexPhase(CompactionEntryLog compactionLog) { - super(compactionLog); - } - - @Override - void start() throws IOException { - compactionLog.makeAvailable(); - assertTrue(offsets.size() > 1); - // only flush index for one entry location - EntryLocation el = offsets.get(0); - ledgerStorage.updateEntriesLocations(offsets); - ledgerStorage.flushEntriesLocationsIndex(); - throw new IOException("Flush ledger index encounter exception"); - } - } - - private class LogFlushFailurePhase extends FlushCompactionLogPhase { - - LogFlushFailurePhase(CompactionEntryLog compactionEntryLog) { - super(compactionEntryLog); - } - - @Override - void start() throws IOException { - // flush the current compaction log - compactionLog.flush(); - throw new IOException("Encounter IOException when trying to flush compaction log"); - } - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieIndexDirTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieIndexDirTest.java deleted file mode 100644 index 3caf076082e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieIndexDirTest.java +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.UpgradeTest.initV1JournalDirectory; -import static org.apache.bookkeeper.bookie.UpgradeTest.initV1LedgerDirectory; -import static org.apache.bookkeeper.bookie.UpgradeTest.initV2JournalDirectory; -import static org.apache.bookkeeper.bookie.UpgradeTest.initV2LedgerDirectory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Sets; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; -import org.apache.bookkeeper.bookie.BookieException.InvalidCookieException; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.util.PortManager; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cookies. - */ -public class CookieIndexDirTest extends BookKeeperClusterTestCase { - - final int bookiePort = PortManager.nextFreePort(); - - public CookieIndexDirTest() { - super(0); - } - - private String newDirectory() throws Exception { - return newDirectory(true); - } - - private String newDirectory(boolean createCurDir) throws Exception { - File d = tmpDirs.createNew("cookie", "tmpdir"); - if (createCurDir) { - new File(d, "current").mkdirs(); - } - return d.getPath(); - } - - MetadataBookieDriver metadataBookieDriver; - RegistrationManager rm; - - @Override - public void setUp() throws Exception { - super.setUp(); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - this.metadataBookieDriver = MetadataDrivers.getBookieDriver( - URI.create(baseConf.getMetadataServiceUri())); - this.metadataBookieDriver.initialize(baseConf, NullStatsLogger.INSTANCE); - this.rm = metadataBookieDriver.createRegistrationManager(); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - if (rm != null) { - rm.close(); - } - if (metadataBookieDriver != null) { - metadataBookieDriver.close(); - } - } - - private static List currentDirectoryList(File[] dirs) { - return Arrays.asList(BookieImpl.getCurrentDirectories(dirs)); - } - - private void validateConfig(ServerConfiguration conf) throws Exception { - List dirs = new ArrayList<>(); - for (File f : conf.getJournalDirs()) { - File cur = BookieImpl.getCurrentDirectory(f); - dirs.add(cur); - BookieImpl.checkDirectoryStructure(cur); - } - for (File f : conf.getLedgerDirs()) { - File cur = BookieImpl.getCurrentDirectory(f); - dirs.add(cur); - BookieImpl.checkDirectoryStructure(cur); - } - if (conf.getIndexDirs() != null) { - for (File f : conf.getIndexDirs()) { - File cur = BookieImpl.getCurrentDirectory(f); - dirs.add(cur); - BookieImpl.checkDirectoryStructure(cur); - } - } - LegacyCookieValidation cookieValidation = new LegacyCookieValidation(conf, rm); - cookieValidation.checkCookies(dirs); - - } - - /** - * Test starting bookie with clean state. - */ - @Test - public void testCleanStart() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory(true)) - .setLedgerDirNames(new String[] { newDirectory(true) }) - .setIndexDirName(new String[] { newDirectory(true) }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - } - - /** - * Test that if a zookeeper cookie - * is different to a local cookie, the bookie - * will fail to start. - */ - @Test - public void testBadJournalCookie() throws Exception { - ServerConfiguration conf1 = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() }) - .setIndexDirName(new String[] { newDirectory() }) - .setBookiePort(bookiePort); - Cookie.Builder cookieBuilder = Cookie.generateCookie(conf1); - Cookie c = cookieBuilder.build(); - c.writeToRegistrationManager(rm, conf1, Version.NEW); - - String journalDir = newDirectory(); - String ledgerDir = newDirectory(); - String indexDir = newDirectory(); - ServerConfiguration conf2 = TestBKConfiguration.newServerConfiguration(); - conf2.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir }) - .setIndexDirName(new String[] { indexDir }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - Cookie.Builder cookieBuilder2 = Cookie.generateCookie(conf2); - Cookie c2 = cookieBuilder2.build(); - c2.writeToDirectory(new File(journalDir, "current")); - c2.writeToDirectory(new File(ledgerDir, "current")); - c2.writeToDirectory(new File(indexDir, "current")); - - try { - validateConfig(conf2); - - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a directory is removed from - * the configuration, the bookie will fail to - * start. - */ - @Test - public void testDirectoryMissing() throws Exception { - String[] ledgerDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - conf.setLedgerDirNames(new String[] { ledgerDirs[0], ledgerDirs[1] }); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - - conf.setIndexDirName(new String[] { indexDirs[0], indexDirs[1] }).setLedgerDirNames(ledgerDirs); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - - conf.setJournalDirName(newDirectory()).setLedgerDirNames(ledgerDirs).setIndexDirName(indexDirs); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - - conf.setJournalDirName(journalDir); - validateConfig(conf); - } - - /** - * Test that if a cookie is missing from a journal directory - * the bookie will fail to start. - */ - @Test - public void testCookieMissingOnJournalDir() throws Exception { - String[] ledgerDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - File cookieFile = - new File(BookieImpl.getCurrentDirectory(new File(journalDir)), BookKeeperConstants.VERSION_FILENAME); - assertTrue(cookieFile.delete()); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a cookie is missing from a ledger directory - * the bookie will fail to start. - */ - @Test - public void testCookieMissingOnLedgerDir() throws Exception { - String[] ledgerDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - File cookieFile = - new File(BookieImpl.getCurrentDirectory(new File(ledgerDirs[0])), BookKeeperConstants.VERSION_FILENAME); - assertTrue(cookieFile.delete()); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a cookie is missing from a index directory - * the bookie will fail to start. - */ - @Test - public void testCookieMissingOnIndexDir() throws Exception { - String[] ledgerDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - File cookieFile = - new File(BookieImpl.getCurrentDirectory(new File(indexDirs[0])), BookKeeperConstants.VERSION_FILENAME); - assertTrue(cookieFile.delete()); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a ledger directory is added to a - * preexisting bookie, the bookie will fail - * to start. - */ - @Test - public void testLedgerDirectoryAdded() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setIndexDirName(new String[] { indexDir0 }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - conf.setLedgerDirNames(new String[] { ledgerDir0, newDirectory() }); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - - conf.setLedgerDirNames(new String[] { ledgerDir0 }); - validateConfig(conf); - } - - /** - * Test that if a index directory is added to a - * preexisting bookie, the bookie will fail - * to start. - */ - @Test - public void testIndexDirectoryAdded() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setIndexDirName(new String[] { indexDir0 }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - conf.setIndexDirName(new String[] { indexDir0, newDirectory() }); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - - conf.setIndexDirName(new String[] { indexDir0 }); - validateConfig(conf); - } - - /** - * Test that if a ledger directory is added to an existing bookie, and - * allowStorageExpansion option is true, the bookie should come online. - */ - @Test - public void testLedgerStorageExpansionOption() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setIndexDirName(new String[] { indexDir0 }) - .setBookiePort(bookiePort) - .setAllowStorageExpansion(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - // add a few additional ledger dirs - String[] lPaths = new String[] {ledgerDir0, newDirectory(), newDirectory()}; - Set configuredLedgerDirs = Sets.newHashSet(lPaths); - conf.setLedgerDirNames(lPaths); - - // add an extra index dir - String[] iPaths = new String[] {indexDir0, newDirectory()}; - Set configuredIndexDirs = Sets.newHashSet(iPaths); - conf.setIndexDirName(iPaths); - - try { - validateConfig(conf); - } catch (InvalidCookieException ice) { - fail("Should have been able to start the bookie"); - } - - List l = currentDirectoryList(conf.getLedgerDirs()); - HashSet bookieLedgerDirs = Sets.newHashSet(); - for (File f : l) { - // Using the parent path because the bookie creates a 'current' - // dir under the ledger dir user provides - bookieLedgerDirs.add(f.getParent()); - } - assertTrue("Configured ledger dirs: " + configuredLedgerDirs + " doesn't match bookie's ledger dirs: " - + bookieLedgerDirs, - configuredLedgerDirs.equals(bookieLedgerDirs)); - - l = currentDirectoryList(conf.getIndexDirs()); - HashSet bookieIndexDirs = Sets.newHashSet(); - for (File f : l) { - bookieIndexDirs.add(f.getParent()); - } - assertTrue("Configured Index dirs: " + configuredIndexDirs + " doesn't match bookie's index dirs: " - + bookieIndexDirs, - configuredIndexDirs.equals(bookieIndexDirs)); - - // Make sure that substituting an older ledger directory - // is not allowed. - String[] lPaths2 = new String[] { lPaths[0], lPaths[1], newDirectory() }; - conf.setLedgerDirNames(lPaths2); - try { - validateConfig(conf); - fail("Should not have been able to start the bookie"); - } catch (InvalidCookieException ice) { - // correct behavior - } - - // Finally make sure that not including the older ledger directories - // is not allowed. Remove one of the older ledger dirs - lPaths2 = new String[] { lPaths[0], lPaths[1] }; - conf.setLedgerDirNames(lPaths2); - try { - validateConfig(conf); - fail("Should not have been able to start the bookie"); - } catch (InvalidCookieException ice) { - // correct behavior - } - } - - /** - * Test that if a ledger directory is added to an existing bookie, and - * allowStorageExpansion option is true, the bookie should come online. - */ - @Test - public void testIndexStorageExpansionOption() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setIndexDirName(new String[] { indexDir0 }) - .setBookiePort(bookiePort) - .setAllowStorageExpansion(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - // add an extra index dir - String[] iPaths = new String[] {indexDir0, newDirectory(), newDirectory()}; - Set configuredIndexDirs = Sets.newHashSet(iPaths); - conf.setIndexDirName(iPaths); - - try { - validateConfig(conf); - } catch (InvalidCookieException ice) { - fail("Should have been able to start the bookie"); - } - - List l = currentDirectoryList(conf.getIndexDirs()); - HashSet bookieIndexDirs = Sets.newHashSet(); - for (File f : l) { - bookieIndexDirs.add(f.getParent()); - } - assertTrue("Configured Index dirs: " + configuredIndexDirs + " doesn't match bookie's index dirs: " - + bookieIndexDirs, - configuredIndexDirs.equals(bookieIndexDirs)); - - // Make sure that substituting an older index directory - // is not allowed. - String[] iPaths2 = new String[] { iPaths[0], iPaths[1], newDirectory() }; - conf.setIndexDirName(iPaths2); - try { - validateConfig(conf); - fail("Should not have been able to start the bookie"); - } catch (InvalidCookieException ice) { - // correct behavior - } - - // Finally make sure that not including the older index directories - // is not allowed. Remove one of the older index dirs - iPaths2 = new String[] { iPaths[0], iPaths[1] }; - conf.setIndexDirName(iPaths2); - try { - validateConfig(conf); - fail("Should not have been able to start the bookie"); - } catch (InvalidCookieException ice) { - // correct behavior - } - } - - /** - * Test that adding of a non-empty directory is not allowed - * even when allowStorageExpansion option is true. - */ - @Test - public void testNonEmptyDirAddWithStorageExpansionOption() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setIndexDirName(new String[] { indexDir0 }) - .setBookiePort(bookiePort) - .setAllowStorageExpansion(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - // add an additional ledger dir - String[] lPaths = new String[] {ledgerDir0, newDirectory()}; - conf.setLedgerDirNames(lPaths); - - // create a file to make the dir non-empty - File currentDir = BookieImpl.getCurrentDirectory(new File(lPaths[1])); - new File(currentDir, "foo").createNewFile(); - assertTrue(currentDir.list().length == 1); - - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behavior - } - - // Now test with a non-empty index dir - String[] iPaths = new String[] {indexDir0, newDirectory()}; - conf.setIndexDirName(iPaths); - - // create a dir to make it non-empty - currentDir = BookieImpl.getCurrentDirectory(new File(iPaths[1])); - new File(currentDir, "bar").mkdirs(); - assertTrue(currentDir.list().length == 1); - - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behavior - } - } - - /** - * Test that if a directory's contents - * are emptied, the bookie will fail to start. - */ - @Test - public void testLedgerDirectoryCleared() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 , newDirectory() }) - .setIndexDirName(new String[] { indexDir }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - FileUtils.deleteDirectory(new File(ledgerDir0)); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a directory's contents - * are emptied, the bookie will fail to start. - */ - @Test - public void testIndexDirectoryCleared() throws Exception { - String ledgerDir = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir }) - .setIndexDirName(new String[] { indexDir0 , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - FileUtils.deleteDirectory(new File(indexDir0)); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a bookie's port is changed - * the bookie will fail to start. - */ - @Test - public void testBookiePortChanged() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setIndexDirName(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - - conf.setBookiePort(3182); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a bookie tries to start - * with the address of a bookie which has already - * existed in the system, then the bookie will fail - * to start. - */ - @Test - public void testNewBookieStartingWithAnotherBookiesPort() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setIndexDirName(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - - conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setIndexDirName(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test Cookie verification with format. - */ - @Test - public void testVerifyCookieWithFormat() throws Exception { - ServerConfiguration adminConf = new ServerConfiguration(); - adminConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - adminConf.setProperty("bookkeeper.format", true); - // Format the BK Metadata and generate INSTANCEID - BookKeeperAdmin.format(adminConf, false, true); - - ServerConfiguration bookieConf = TestBKConfiguration.newServerConfiguration(); - bookieConf.setJournalDirName(newDirectory(true)) - .setLedgerDirNames(new String[] { newDirectory(true) }) - .setIndexDirName(new String[] { newDirectory(true) }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - // Bookie should start successfully for fresh env. - validateConfig(bookieConf); - - // Format metadata one more time. - BookKeeperAdmin.format(adminConf, false, true); - try { - validateConfig(bookieConf); - fail("Bookie should not start with previous instance id."); - } catch (InvalidCookieException e) { - assertTrue( - "Bookie startup should fail because of invalid instance id", - e.getMessage().contains("instanceId")); - } - - // Now format the Bookie and restart. - BookieImpl.format(bookieConf, false, true); - // After bookie format bookie should be able to start again. - validateConfig(bookieConf); - } - - /** - * Test that if a bookie is started with directories with - * version 2 data, that it will fail to start (it needs upgrade). - */ - @Test - public void testV2data() throws Exception { - File journalDir = initV2JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV2LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setIndexDirName(new String[] { ledgerDir.getPath() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - } - - /** - * Test that if a bookie is started with directories with - * version 1 data, that it will fail to start (it needs upgrade). - */ - @Test - public void testV1data() throws Exception { - File journalDir = initV1JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV1LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir.getPath()}) - .setIndexDirName(new String[]{ledgerDir.getPath()}) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - } - - /** - * Test restart bookie with useHostNameAsBookieID=true, which had cookie generated - * with ipaddress. - */ - @Test - public void testRestartWithHostNameAsBookieID() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - - conf.setUseHostNameAsBookieID(true); - try { - validateConfig(conf); - fail("Should not start a bookie with hostname if the bookie has been started with an ip"); - } catch (InvalidCookieException e) { - // expected - } - } - - /** - * Test restart bookie with new advertisedAddress, which had cookie generated with ip. - */ - @Test - public void testRestartWithAdvertisedAddressAsBookieID() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setUseHostNameAsBookieID(false); - validateConfig(conf); - - conf.setAdvertisedAddress("unknown"); - try { - validateConfig(conf); - fail("Should not start a bookie with ip if the bookie has been started with an ip"); - } catch (InvalidCookieException e) { - // expected - } - } - - /** - * Test restart bookie with useHostNameAsBookieID=false, which had cookie generated - * with hostname. - */ - @Test - public void testRestartWithIpAddressAsBookieID() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setUseHostNameAsBookieID(true); - validateConfig(conf); - - conf.setUseHostNameAsBookieID(false); - try { - validateConfig(conf); - fail("Should not start a bookie with ip if the bookie has been started with an ip"); - } catch (InvalidCookieException e) { - // expected - } - } - - /** - * Test old version bookie starts with the cookies generated by new version - * (with useHostNameAsBookieID=true). - */ - @Test - public void testV2dataWithHostNameAsBookieID() throws Exception { - File journalDir = initV2JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV2LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setIndexDirName(new String[] { ledgerDir.getPath() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - } - - /** - * Test write cookie multiple times. - */ - @Test - public void testWriteToZooKeeper() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - Versioned zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Version version1 = zkCookie.getVersion(); - assertTrue("Invalid type expected ZkVersion type", - version1 instanceof LongVersion); - LongVersion zkVersion1 = (LongVersion) version1; - Cookie cookie = zkCookie.getValue(); - cookie.writeToRegistrationManager(rm, conf, version1); - - zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Version version2 = zkCookie.getVersion(); - assertTrue("Invalid type expected ZkVersion type", version2 instanceof LongVersion); - LongVersion zkVersion2 = (LongVersion) version2; - assertEquals("Version mismatches!", - zkVersion1.getLongVersion() + 1, zkVersion2.getLongVersion()); - } - - /** - * Test delete cookie. - */ - @Test - public void testDeleteFromZooKeeper() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String[] indexDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(indexDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - Versioned zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Cookie cookie = zkCookie.getValue(); - cookie.deleteFromRegistrationManager(rm, conf, zkCookie.getVersion()); - } - - /** - * Tests that custom Bookie Id is properly set in the Cookie (via {@link LegacyCookieValidation}). - */ - @Test - public void testBookieIdSetting() throws Exception { - final String customBookieId = "myCustomBookieId" + new Random().nextInt(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setIndexDirName(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setBookieId(customBookieId) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - Versioned zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Version version1 = zkCookie.getVersion(); - assertTrue("Invalid type expected ZkVersion type", version1 instanceof LongVersion); - Cookie cookie = zkCookie.getValue(); - cookie.writeToRegistrationManager(rm, conf, version1); - Assert.assertTrue(cookie.toString().contains(customBookieId)); - } - - /** - * Compatibility test - * 1. First create bookie without indexDirName - * 2. Configure indexDirName to start bookie - */ - @Test - public void testNewBookieStartingWithOldCookie() throws Exception { - String journalDir = newDirectory(); - String[] ledgerDirs = {newDirectory(), newDirectory()}; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - - conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setIndexDirName(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - validateConfig(conf); - } catch (InvalidCookieException ice) { - // error behaviour - fail("Validate failed, error info: " + ice.getMessage()); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieTest.java deleted file mode 100644 index 9d068ad291a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieTest.java +++ /dev/null @@ -1,782 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.UpgradeTest.initV1JournalDirectory; -import static org.apache.bookkeeper.bookie.UpgradeTest.initV1LedgerDirectory; -import static org.apache.bookkeeper.bookie.UpgradeTest.initV2JournalDirectory; -import static org.apache.bookkeeper.bookie.UpgradeTest.initV2LedgerDirectory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Sets; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; -import org.apache.bookkeeper.bookie.BookieException.InvalidCookieException; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.util.PortManager; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test cookies. - */ -public class CookieTest extends BookKeeperClusterTestCase { - private static final Logger log = LoggerFactory.getLogger(CookieTest.class); - - final int bookiePort = PortManager.nextFreePort(); - - public CookieTest() { - super(0); - } - - private String newDirectory() throws Exception { - return newDirectory(true); - } - - private String newDirectory(boolean createCurDir) throws Exception { - File d = tmpDirs.createNew("cookie", "tmpdir"); - if (createCurDir) { - new File(d, "current").mkdirs(); - } - return d.getPath(); - } - - MetadataBookieDriver metadataBookieDriver; - RegistrationManager rm; - - @Override - public void setUp() throws Exception { - super.setUp(); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - this.metadataBookieDriver = MetadataDrivers.getBookieDriver( - URI.create(baseConf.getMetadataServiceUri())); - this.metadataBookieDriver.initialize(baseConf, NullStatsLogger.INSTANCE); - this.rm = metadataBookieDriver.createRegistrationManager(); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - if (rm != null) { - rm.close(); - } - if (metadataBookieDriver != null) { - metadataBookieDriver.close(); - } - } - - private static List currentDirectoryList(File[] dirs) { - return Arrays.asList(BookieImpl.getCurrentDirectories(dirs)); - } - - private void validateConfig(ServerConfiguration conf) throws Exception { - List dirs = new ArrayList<>(); - for (File f : conf.getJournalDirs()) { - File cur = BookieImpl.getCurrentDirectory(f); - dirs.add(cur); - BookieImpl.checkDirectoryStructure(cur); - } - for (File f : conf.getLedgerDirs()) { - File cur = BookieImpl.getCurrentDirectory(f); - dirs.add(cur); - BookieImpl.checkDirectoryStructure(cur); - } - LegacyCookieValidation cookieValidation = new LegacyCookieValidation(conf, rm); - cookieValidation.checkCookies(dirs); - - } - - /** - * Test starting bookie with clean state. - */ - @Test - public void testCleanStart() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory(true)) - .setLedgerDirNames(new String[] { newDirectory(true) }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - } - - /** - * Test that if a zookeeper cookie - * is different to a local cookie, the bookie - * will fail to start. - */ - @Test - public void testBadJournalCookie() throws Exception { - ServerConfiguration conf1 = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() }) - .setBookiePort(bookiePort); - Cookie.Builder cookieBuilder = Cookie.generateCookie(conf1); - Cookie c = cookieBuilder.build(); - c.writeToRegistrationManager(rm, conf1, Version.NEW); - - String journalDir = newDirectory(); - String ledgerDir = newDirectory(); - ServerConfiguration conf2 = TestBKConfiguration.newServerConfiguration(); - conf2.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - Cookie.Builder cookieBuilder2 = Cookie.generateCookie(conf2); - Cookie c2 = cookieBuilder2.build(); - c2.writeToDirectory(new File(journalDir, "current")); - c2.writeToDirectory(new File(ledgerDir, "current")); - - try { - validateConfig(conf2); - - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a directory is removed from - * the configuration, the bookie will fail to - * start. - */ - @Test - public void testDirectoryMissing() throws Exception { - String[] ledgerDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - conf.setLedgerDirNames(new String[] { ledgerDirs[0], ledgerDirs[1] }); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - - conf.setJournalDirName(newDirectory()).setLedgerDirNames(ledgerDirs); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - - conf.setJournalDirName(journalDir); - validateConfig(conf); - } - - /** - * Test that if a cookie is missing from a journal directory - * the bookie will fail to start. - */ - @Test - public void testCookieMissingOnJournalDir() throws Exception { - String[] ledgerDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - File cookieFile = - new File(BookieImpl.getCurrentDirectory(new File(journalDir)), BookKeeperConstants.VERSION_FILENAME); - assertTrue(cookieFile.delete()); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a cookie is missing from a journal directory - * the bookie will fail to start. - */ - @Test - public void testCookieMissingOnLedgerDir() throws Exception { - String[] ledgerDirs = new String[] { - newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - File cookieFile = - new File(BookieImpl.getCurrentDirectory(new File(ledgerDirs[0])), BookKeeperConstants.VERSION_FILENAME); - assertTrue(cookieFile.delete()); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a directory is added to a - * preexisting bookie, the bookie will fail - * to start. - */ - @Test - public void testDirectoryAdded() throws Exception { - String ledgerDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - conf.setLedgerDirNames(new String[] { ledgerDir0, newDirectory() }); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - - conf.setLedgerDirNames(new String[] { ledgerDir0 }); - validateConfig(conf); - } - - /** - * Test that if a directory is added to an existing bookie, and - * allowStorageExpansion option is true, the bookie should come online. - */ - @Test - public void testStorageExpansionOption() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setIndexDirName(new String[] { indexDir0 }) - .setBookiePort(bookiePort) - .setAllowStorageExpansion(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - // add a few additional ledger dirs - String[] lPaths = new String[] {ledgerDir0, newDirectory(), newDirectory()}; - Set configuredLedgerDirs = Sets.newHashSet(lPaths); - conf.setLedgerDirNames(lPaths); - - // add an extra index dir - String[] iPaths = new String[] {indexDir0, newDirectory()}; - Set configuredIndexDirs = Sets.newHashSet(iPaths); - conf.setIndexDirName(iPaths); - - try { - validateConfig(conf); - } catch (BookieException.InvalidCookieException ice) { - fail("Should have been able to start the bookie"); - } - - List l = currentDirectoryList(conf.getLedgerDirs()); - HashSet bookieLedgerDirs = Sets.newHashSet(); - for (File f : l) { - // Using the parent path because the bookie creates a 'current' - // dir under the ledger dir user provides - bookieLedgerDirs.add(f.getParent()); - } - assertTrue("Configured ledger dirs: " + configuredLedgerDirs + " doesn't match bookie's ledger dirs: " - + bookieLedgerDirs, - configuredLedgerDirs.equals(bookieLedgerDirs)); - - l = currentDirectoryList(conf.getIndexDirs()); - HashSet bookieIndexDirs = Sets.newHashSet(); - for (File f : l) { - bookieIndexDirs.add(f.getParent()); - } - assertTrue("Configured Index dirs: " + configuredIndexDirs + " doesn't match bookie's index dirs: " - + bookieIndexDirs, - configuredIndexDirs.equals(bookieIndexDirs)); - - // Make sure that substituting an older ledger directory - // is not allowed. - String[] lPaths2 = new String[] { lPaths[0], lPaths[1], newDirectory() }; - conf.setLedgerDirNames(lPaths2); - try { - validateConfig(conf); - fail("Should not have been able to start the bookie"); - } catch (BookieException.InvalidCookieException ice) { - // correct behavior - } - - // Finally make sure that not including the older ledger directories - // is not allowed. Remove one of the older ledger dirs - lPaths2 = new String[] { lPaths[0], lPaths[1] }; - conf.setLedgerDirNames(lPaths2); - try { - validateConfig(conf); - fail("Should not have been able to start the bookie"); - } catch (BookieException.InvalidCookieException ice) { - // correct behavior - } - } - - /** - * Test that adding of a non-empty directory is not allowed - * even when allowStorageExpansion option is true. - */ - @Test - public void testNonEmptyDirAddWithStorageExpansionOption() throws Exception { - String ledgerDir0 = newDirectory(); - String indexDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 }) - .setIndexDirName(new String[] { indexDir0 }) - .setBookiePort(bookiePort) - .setAllowStorageExpansion(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - // add an additional ledger dir - String[] lPaths = new String[] {ledgerDir0, newDirectory()}; - conf.setLedgerDirNames(lPaths); - - // create a file to make the dir non-empty - File currentDir = BookieImpl.getCurrentDirectory(new File(lPaths[1])); - new File(currentDir, "foo").createNewFile(); - assertTrue(currentDir.list().length == 1); - - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behavior - } - - // Now test with a non-empty index dir - String[] iPaths = new String[] {indexDir0, newDirectory()}; - conf.setIndexDirName(iPaths); - - // create a dir to make it non-empty - currentDir = BookieImpl.getCurrentDirectory(new File(iPaths[1])); - new File(currentDir, "bar").mkdirs(); - assertTrue(currentDir.list().length == 1); - - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behavior - } - } - - /** - * Test that if a directory's contents - * are emptied, the bookie will fail to start. - */ - @Test - public void testDirectoryCleared() throws Exception { - String ledgerDir0 = newDirectory(); - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[] { ledgerDir0 , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - validateConfig(conf); - - FileUtils.deleteDirectory(new File(ledgerDir0)); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a bookie's port is changed - * the bookie will fail to start. - */ - @Test - public void testBookiePortChanged() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - - conf.setBookiePort(3182); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test that if a bookie tries to start - * with the address of a bookie which has already - * existed in the system, then the bookie will fail - * to start. - */ - @Test - public void testNewBookieStartingWithAnotherBookiesPort() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - - conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - validateConfig(conf); - fail("Shouldn't have been able to start"); - } catch (BookieException.InvalidCookieException ice) { - // correct behaviour - } - } - - /** - * Test Cookie verification with format. - */ - @Test - public void testVerifyCookieWithFormat() throws Exception { - ServerConfiguration adminConf = new ServerConfiguration(); - adminConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - adminConf.setProperty("bookkeeper.format", true); - // Format the BK Metadata and generate INSTANCEID - BookKeeperAdmin.format(adminConf, false, true); - - ServerConfiguration bookieConf = TestBKConfiguration.newServerConfiguration(); - bookieConf.setJournalDirName(newDirectory(true)) - .setLedgerDirNames(new String[] { newDirectory(true) }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - // Bookie should start successfully for fresh env. - validateConfig(bookieConf); - - // Format metadata one more time. - BookKeeperAdmin.format(adminConf, false, true); - try { - validateConfig(bookieConf); - fail("Bookie should not start with previous instance id."); - } catch (BookieException.InvalidCookieException e) { - assertTrue( - "Bookie startup should fail because of invalid instance id", - e.getMessage().contains("instanceId")); - } - - // Now format the Bookie and restart. - BookieImpl.format(bookieConf, false, true); - // After bookie format bookie should be able to start again. - validateConfig(bookieConf); - } - - /** - * Test that if a bookie is started with directories with - * version 2 data, that it will fail to start (it needs upgrade). - */ - @Test - public void testV2data() throws Exception { - File journalDir = initV2JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV2LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - } - - /** - * Test that if a bookie is started with directories with - * version 1 data, that it will fail to start (it needs upgrade). - */ - @Test - public void testV1data() throws Exception { - File journalDir = initV1JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV1LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir.getPath()}) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - } - - /** - * Test restart bookie with useHostNameAsBookieID=true, which had cookie generated - * with ipaddress. - */ - @Test - public void testRestartWithHostNameAsBookieID() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), - newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - - conf.setUseHostNameAsBookieID(true); - try { - validateConfig(conf); - fail("Should not start a bookie with hostname if the bookie has been started with an ip"); - } catch (InvalidCookieException e) { - // expected - } - } - - /** - * Test restart bookie with new advertisedAddress, which had cookie generated with ip. - */ - @Test - public void testRestartWithAdvertisedAddressAsBookieID() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), - newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setUseHostNameAsBookieID(false); - validateConfig(conf); - - conf.setAdvertisedAddress("unknown"); - try { - validateConfig(conf); - fail("Should not start a bookie with ip if the bookie has been started with an ip"); - } catch (InvalidCookieException e) { - // expected - } - } - - /** - * Test restart bookie with useHostNameAsBookieID=false, which had cookie generated - * with hostname. - */ - @Test - public void testRestartWithIpAddressAsBookieID() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), - newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir).setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setUseHostNameAsBookieID(true); - validateConfig(conf); - - conf.setUseHostNameAsBookieID(false); - try { - validateConfig(conf); - fail("Should not start a bookie with ip if the bookie has been started with an ip"); - } catch (InvalidCookieException e) { - // expected - } - } - - /** - * Test old version bookie starts with the cookies generated by new version - * (with useHostNameAsBookieID=true). - */ - @Test - public void testV2dataWithHostNameAsBookieID() throws Exception { - File journalDir = initV2JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV2LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - - try { - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - fail("Shouldn't have been able to start"); - } catch (IOException ioe) { - // correct behaviour - assertTrue("wrong exception", ioe.getMessage().contains("upgrade needed")); - } - } - - /** - * Test write cookie multiple times. - */ - @Test - public void testWriteToZooKeeper() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - Versioned zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Version version1 = zkCookie.getVersion(); - assertTrue("Invalid type expected ZkVersion type", - version1 instanceof LongVersion); - LongVersion zkVersion1 = (LongVersion) version1; - Cookie cookie = zkCookie.getValue(); - cookie.writeToRegistrationManager(rm, conf, version1); - - zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Version version2 = zkCookie.getVersion(); - assertTrue("Invalid type expected ZkVersion type", - version2 instanceof LongVersion); - LongVersion zkVersion2 = (LongVersion) version2; - assertEquals("Version mismatches!", - zkVersion1.getLongVersion() + 1, zkVersion2.getLongVersion()); - } - - /** - * Test delete cookie. - */ - @Test - public void testDeleteFromZooKeeper() throws Exception { - String[] ledgerDirs = new String[] { newDirectory(), newDirectory(), newDirectory() }; - String journalDir = newDirectory(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(ledgerDirs) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - Versioned zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Cookie cookie = zkCookie.getValue(); - cookie.deleteFromRegistrationManager(rm, conf, zkCookie.getVersion()); - } - - /** - * Tests that custom Bookie Id is properly set in the Cookie (via {@link LegacyCookieValidation}). - */ - @Test - public void testBookieIdSetting() throws Exception { - final String customBookieId = "myCustomBookieId" + new Random().nextInt(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(newDirectory()) - .setLedgerDirNames(new String[] { newDirectory() , newDirectory() }) - .setBookiePort(bookiePort) - .setBookieId(customBookieId) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - validateConfig(conf); - Versioned zkCookie = Cookie.readFromRegistrationManager(rm, conf); - Version version1 = zkCookie.getVersion(); - assertTrue("Invalid type expected ZkVersion type", - version1 instanceof LongVersion); - Cookie cookie = zkCookie.getValue(); - cookie.writeToRegistrationManager(rm, conf, version1); - Assert.assertTrue(cookie.toString().contains(customBookieId)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CreateNewLogTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CreateNewLogTest.java deleted file mode 100644 index 4d7015876b7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CreateNewLogTest.java +++ /dev/null @@ -1,929 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertTrue; - -import com.google.common.util.concurrent.MoreExecutors; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Lock; -import java.util.stream.IntStream; -import org.apache.bookkeeper.bookie.EntryLogManagerForEntryLogPerLedger.BufferedLogChannelWithDirInfo; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.lang.mutable.MutableInt; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test new log creation. - */ -public class CreateNewLogTest { - private static final Logger LOG = LoggerFactory - .getLogger(CreateNewLogTest.class); - - private String[] ledgerDirs; - private int numDirs = 100; - - @Before - public void setUp() throws Exception{ - ledgerDirs = new String[numDirs]; - for (int i = 0; i < numDirs; i++){ - File temp = File.createTempFile("bookie", "test"); - temp.delete(); - temp.mkdir(); - File currentTemp = new File(temp.getAbsoluteFile() + "/current"); - currentTemp.mkdir(); - ledgerDirs[i] = temp.getPath(); - } - } - - @After - public void tearDown() throws Exception{ - for (int i = 0; i < numDirs; i++){ - File f = new File(ledgerDirs[i]); - deleteRecursive(f); - } - } - - private void deleteRecursive(File f) { - if (f.isDirectory()){ - for (File c : f.listFiles()){ - deleteRecursive(c); - } - } - - f.delete(); - } - - /** - * Checks if new log file id is verified against all directories. - * - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-465} - * - * @throws Exception - */ - @Test - public void testCreateNewLog() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of - // ledger directories. - conf.setLedgerDirNames(ledgerDirs); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - // Extracted from createNewLog() - String logFileName = Long.toHexString(1) + ".log"; - File dir = ledgerDirsManager.pickRandomWritableDir(); - LOG.info("Picked this directory: {}", dir); - File newLogFile = new File(dir, logFileName); - newLogFile.createNewFile(); - - DefaultEntryLogger el = new DefaultEntryLogger(conf, ledgerDirsManager); - // Calls createNewLog, and with the number of directories we - // are using, if it picks one at random it will fail. - EntryLogManagerForSingleEntryLog entryLogManager = (EntryLogManagerForSingleEntryLog) el.getEntryLogManager(); - entryLogManager.createNewLog(0L); - LOG.info("This is the current log id: {}", entryLogManager.getCurrentLogId()); - assertTrue("Wrong log id", entryLogManager.getCurrentLogId() > 1); - } - - @Test - public void testCreateNewLogWithNoWritableLedgerDirs() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of ledger directories. - conf.setLedgerDirNames(ledgerDirs); - conf.setIsForceGCAllowWhenNoSpace(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - // Extracted from createNewLog() - String logFileName = Long.toHexString(1) + ".log"; - File dir = ledgerDirsManager.pickRandomWritableDir(); - LOG.info("Picked this directory: {}", dir); - File newLogFile = new File(dir, logFileName); - newLogFile.createNewFile(); - - // Now let us move all dirs to filled dirs - List wDirs = ledgerDirsManager.getWritableLedgerDirs(); - for (File tdir: wDirs) { - ledgerDirsManager.addToFilledDirs(tdir); - } - - DefaultEntryLogger el = new DefaultEntryLogger(conf, ledgerDirsManager); - // Calls createNewLog, and with the number of directories we - // are using, if it picks one at random it will fail. - EntryLogManagerForSingleEntryLog entryLogManager = (EntryLogManagerForSingleEntryLog) el.getEntryLogManager(); - entryLogManager.createNewLog(0L); - LOG.info("This is the current log id: {}", entryLogManager.getCurrentLogId()); - assertTrue("Wrong log id", entryLogManager.getCurrentLogId() > 1); - } - - void setSameThreadExecutorForEntryLoggerAllocator(EntryLoggerAllocator entryLoggerAllocator) { - ExecutorService executorService = entryLoggerAllocator.allocatorExecutor; - executorService.shutdown(); - entryLoggerAllocator.allocatorExecutor = MoreExecutors.newDirectExecutorService(); - } - - /* - * entryLogPerLedger is enabled and various scenarios of entrylogcreation are tested - */ - @Test - public void testEntryLogPerLedgerCreationWithPreAllocation() throws Exception { - /* - * I wish I could shorten this testcase or split it into multiple testcases, - * but I want to cover a scenario and it requires multiple operations in - * sequence and validations along the way. Please bear with the length of this - * testcase, I added as many comments as I can to simplify it. - */ - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of ledger directories. - conf.setLedgerDirNames(ledgerDirs); - conf.setIsForceGCAllowWhenNoSpace(true); - // preAllocation is Enabled - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLoggerAllocator entryLoggerAllocator = entryLogger.entryLoggerAllocator; - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) entryLogger - .getEntryLogManager(); - // set same thread executor for entryLoggerAllocator's allocatorExecutor - setSameThreadExecutorForEntryLoggerAllocator(entryLoggerAllocator); - - /* - * no entrylog will be created during initialization - */ - int expectedPreAllocatedLogID = -1; - Assert.assertEquals("PreallocatedlogId after initialization of Entrylogger", - expectedPreAllocatedLogID, entryLoggerAllocator.getPreallocatedLogId()); - - int numOfLedgers = 6; - - for (long i = 0; i < numOfLedgers; i++) { - /* since we are starting creation of new ledgers, entrylogid will be ledgerid */ - entryLogManager.createNewLog(i); - } - - /* - * preallocation is enabled so though entryLogId starts with 0, preallocatedLogId would be equal to numOfLedgers - */ - expectedPreAllocatedLogID = numOfLedgers; - Assert.assertEquals("PreallocatedlogId after creation of logs for ledgers", expectedPreAllocatedLogID, - entryLoggerAllocator.getPreallocatedLogId()); - Assert.assertEquals("Number of current ", numOfLedgers, - entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of LogChannels to flush", 0, - entryLogManager.getRotatedLogChannels().size()); - - // create dummy entrylog file with id - (expectedPreAllocatedLogID + 1) - String logFileName = Long.toHexString(expectedPreAllocatedLogID + 1) + ".log"; - File dir = ledgerDirsManager.pickRandomWritableDir(); - LOG.info("Picked this directory: " + dir); - File newLogFile = new File(dir, logFileName); - newLogFile.createNewFile(); - - /* - * since there is already preexisting entrylog file with id - - * (expectedPreAllocatedLogIDDuringInitialization + 1), when new - * entrylog is created it should have - * (expectedPreAllocatedLogIDDuringInitialization + 2) id - */ - long rotatedLedger = 1L; - entryLogManager.createNewLog(rotatedLedger); - - expectedPreAllocatedLogID = expectedPreAllocatedLogID + 2; - Assert.assertEquals("PreallocatedlogId ", - expectedPreAllocatedLogID, entryLoggerAllocator.getPreallocatedLogId()); - Assert.assertEquals("Number of current ", numOfLedgers, - entryLogManager.getCopyOfCurrentLogs().size()); - List rotatedLogChannels = entryLogManager.getRotatedLogChannels(); - Assert.assertEquals("Number of LogChannels rotated", 1, rotatedLogChannels.size()); - Assert.assertEquals("Rotated logchannel logid", rotatedLedger, rotatedLogChannels.iterator().next().getLogId()); - entryLogger.flush(); - /* - * when flush is called all the rotatedlogchannels are flushed and - * removed from rotatedlogchannels list. But here since entrylogId - 0, - * is not yet rotated and flushed yet, getLeastUnflushedLogId will still - * return 0. - */ - rotatedLogChannels = entryLogManager.getRotatedLogChannels(); - Assert.assertEquals("Number of LogChannels rotated", 0, rotatedLogChannels.size()); - Assert.assertEquals("Least UnflushedLoggerId", 0, entryLogger.getLeastUnflushedLogId()); - - entryLogManager.createNewLog(0L); - rotatedLogChannels = entryLogManager.getRotatedLogChannels(); - Assert.assertEquals("Number of LogChannels rotated", 1, rotatedLogChannels.size()); - Assert.assertEquals("Least UnflushedLoggerId", 0, entryLogger.getLeastUnflushedLogId()); - entryLogger.flush(); - /* - * since both entrylogids 0, 1 are rotated and flushed, - * leastunFlushedLogId should be 2 - */ - Assert.assertEquals("Least UnflushedLoggerId", 2, entryLogger.getLeastUnflushedLogId()); - expectedPreAllocatedLogID = expectedPreAllocatedLogID + 1; - - /* - * we should be able to get entryLogMetadata from all the active - * entrylogs and the logs which are moved toflush list. Since no entry - * is added, all the meta should be empty. - */ - for (int i = 0; i <= expectedPreAllocatedLogID; i++) { - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(i); - Assert.assertTrue("EntryLogMetadata should be empty", meta.isEmpty()); - Assert.assertTrue("EntryLog usage should be 0", meta.getTotalSize() == 0); - } - } - - /** - * In this testcase entryLogPerLedger is Enabled and entrylogs are created - * while ledgerdirs are getting full. - */ - @Test - public void testEntryLogCreationWithFilledDirs() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of ledger directories. - conf.setLedgerDirNames(ledgerDirs); - // forceGCAllowWhenNoSpace is disabled - conf.setIsForceGCAllowWhenNoSpace(false); - // pre-allocation is not enabled - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setEntryLogPerLedgerEnabled(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLoggerAllocator entryLoggerAllocator = entryLogger.entryLoggerAllocator; - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) - entryLogger.getEntryLogManager(); - // set same thread executor for entryLoggerAllocator's allocatorExecutor - setSameThreadExecutorForEntryLoggerAllocator(entryLoggerAllocator); - - int expectedPreAllocatedLogIDDuringInitialization = -1; - Assert.assertEquals("PreallocatedlogId after initialization of Entrylogger", - expectedPreAllocatedLogIDDuringInitialization, entryLoggerAllocator.getPreallocatedLogId()); - Assert.assertEquals("Preallocation Future of this slot should be null", null, - entryLogger.entryLoggerAllocator.preallocation); - - long ledgerId = 0L; - - entryLogManager.createNewLog(ledgerId); - - /* - * pre-allocation is not enabled, so it would not preallocate for next entrylog - */ - Assert.assertEquals("PreallocatedlogId after initialization of Entrylogger", - expectedPreAllocatedLogIDDuringInitialization + 1, entryLoggerAllocator.getPreallocatedLogId()); - - for (int i = 0; i < numDirs - 1; i++) { - ledgerDirsManager.addToFilledDirs(BookieImpl.getCurrentDirectory(new File(ledgerDirs[i]))); - } - - /* - * this is the only non-filled ledgerDir so it should be used for creating new entryLog - */ - File nonFilledLedgerDir = BookieImpl.getCurrentDirectory(new File(ledgerDirs[numDirs - 1])); - - entryLogManager.createNewLog(ledgerId); - DefaultEntryLogger.BufferedLogChannel newLogChannel = entryLogManager.getCurrentLogForLedger(ledgerId); - Assert.assertEquals("Directory of newly created BufferedLogChannel file", nonFilledLedgerDir.getAbsolutePath(), - newLogChannel.getLogFile().getParentFile().getAbsolutePath()); - - ledgerDirsManager.addToFilledDirs(BookieImpl.getCurrentDirectory(new File(ledgerDirs[numDirs - 1]))); - - // new entrylog creation should succeed, though there is no writable ledgerDir - entryLogManager.createNewLog(ledgerId); - } - - /* - * In this testcase it is validated if the entryLog is created in the - * ledgerDir with least number of current active entrylogs - */ - @Test - public void testLedgerDirsUniformityDuringCreation() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of ledger directories. - conf.setLedgerDirNames(ledgerDirs); - // pre-allocation is not enabled - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setEntryLogPerLedgerEnabled(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entrylogManager = (EntryLogManagerForEntryLogPerLedger) - entryLogger.getEntryLogManager(); - - for (long i = 0; i < ledgerDirs.length; i++) { - entrylogManager.createNewLog(i); - } - - int numberOfLedgersCreated = ledgerDirs.length; - - Assert.assertEquals("Highest frequency of entrylogs per ledgerdir", 1, - highestFrequencyOfEntryLogsPerLedgerDir(entrylogManager.getCopyOfCurrentLogs())); - - long newLedgerId = numberOfLedgersCreated; - entrylogManager.createNewLog(newLedgerId); - numberOfLedgersCreated++; - - Assert.assertEquals("Highest frequency of entrylogs per ledgerdir", 2, - highestFrequencyOfEntryLogsPerLedgerDir(entrylogManager.getCopyOfCurrentLogs())); - - for (long i = numberOfLedgersCreated; i < 2 * ledgerDirs.length; i++) { - entrylogManager.createNewLog(i); - } - - Assert.assertEquals("Highest frequency of entrylogs per ledgerdir", 2, - highestFrequencyOfEntryLogsPerLedgerDir(entrylogManager.getCopyOfCurrentLogs())); - } - - - int highestFrequencyOfEntryLogsPerLedgerDir(Set copyOfCurrentLogsWithDirInfo) { - Map frequencyOfEntryLogsInLedgerDirs = new HashMap(); - for (BufferedLogChannelWithDirInfo logChannelWithDirInfo : copyOfCurrentLogsWithDirInfo) { - File parentDir = logChannelWithDirInfo.getLogChannel().getLogFile().getParentFile(); - if (frequencyOfEntryLogsInLedgerDirs.containsKey(parentDir)) { - frequencyOfEntryLogsInLedgerDirs.get(parentDir).increment(); - } else { - frequencyOfEntryLogsInLedgerDirs.put(parentDir, new MutableInt(1)); - } - } - @SuppressWarnings("unchecked") - int highestFreq = ((Entry) (frequencyOfEntryLogsInLedgerDirs.entrySet().stream() - .max(Map.Entry.comparingByValue()).get())).getValue().intValue(); - return highestFreq; - } - - @Test - public void testConcurrentCreateNewLogWithEntryLogFilePreAllocationEnabled() throws Exception { - testConcurrentCreateNewLog(true); - } - - @Test - public void testConcurrentCreateNewLogWithEntryLogFilePreAllocationDisabled() throws Exception { - testConcurrentCreateNewLog(false); - } - - public void testConcurrentCreateNewLog(boolean entryLogFilePreAllocationEnabled) throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of - // ledger directories. - conf.setLedgerDirNames(ledgerDirs); - conf.setEntryLogFilePreAllocationEnabled(entryLogFilePreAllocationEnabled); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger el = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerBase entryLogManager = (EntryLogManagerBase) el.getEntryLogManager(); - // set same thread executor for entryLoggerAllocator's allocatorExecutor - setSameThreadExecutorForEntryLoggerAllocator(el.getEntryLoggerAllocator()); - - Assert.assertEquals("previousAllocatedEntryLogId after initialization", -1, - el.getPreviousAllocatedEntryLogId()); - Assert.assertEquals("leastUnflushedLogId after initialization", 0, el.getLeastUnflushedLogId()); - int createNewLogNumOfTimes = 10; - AtomicBoolean receivedException = new AtomicBoolean(false); - - IntStream.range(0, createNewLogNumOfTimes).parallel().forEach((i) -> { - try { - (entryLogManager).createNewLog((long) i); - } catch (IOException e) { - LOG.error("Received exception while creating newLog", e); - receivedException.set(true); - } - }); - - Assert.assertFalse("There shouldn't be any exceptions while creating newlog", receivedException.get()); - int expectedPreviousAllocatedEntryLogId = createNewLogNumOfTimes - 1; - if (entryLogFilePreAllocationEnabled) { - expectedPreviousAllocatedEntryLogId = createNewLogNumOfTimes; - } - - Assert.assertEquals( - "previousAllocatedEntryLogId after " + createNewLogNumOfTimes - + " number of times createNewLog is called", - expectedPreviousAllocatedEntryLogId, el.getPreviousAllocatedEntryLogId()); - Assert.assertEquals("Number of RotatedLogChannels", createNewLogNumOfTimes - 1, - entryLogManager.getRotatedLogChannels().size()); - } - - @Test - public void testCreateNewLogWithGaps() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of - // ledger directories. - conf.setLedgerDirNames(ledgerDirs); - conf.setEntryLogFilePreAllocationEnabled(false); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger el = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerBase entryLogManagerBase = (EntryLogManagerBase) el.getEntryLogManager(); - entryLogManagerBase.createNewLog(0L); - - Assert.assertEquals("previousAllocatedEntryLogId after initialization", 0, el.getPreviousAllocatedEntryLogId()); - - // Extracted from createNewLog() - String logFileName = Long.toHexString(1) + ".log"; - File dir = ledgerDirsManager.pickRandomWritableDir(); - LOG.info("Picked this directory: {}", dir); - File newLogFile = new File(dir, logFileName); - newLogFile.createNewFile(); - - entryLogManagerBase.createNewLog(0L); - Assert.assertEquals("previousAllocatedEntryLogId since entrylogid 1 is already taken", 2, - el.getPreviousAllocatedEntryLogId()); - - // Extracted from createNewLog() - logFileName = Long.toHexString(3) + ".log"; - dir = ledgerDirsManager.pickRandomWritableDir(); - LOG.info("Picked this directory: {}", dir); - newLogFile = new File(dir, logFileName); - newLogFile.createNewFile(); - - entryLogManagerBase.createNewLog(0L); - Assert.assertEquals("previousAllocatedEntryLogId since entrylogid 3 is already taken", 4, - el.getPreviousAllocatedEntryLogId()); - } - - @Test - public void testCreateNewLogAndCompactionLog() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of - // ledger directories. - conf.setLedgerDirNames(ledgerDirs); - conf.setEntryLogFilePreAllocationEnabled(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger el = new DefaultEntryLogger(conf, ledgerDirsManager); - // set same thread executor for entryLoggerAllocator's allocatorExecutor - setSameThreadExecutorForEntryLoggerAllocator(el.getEntryLoggerAllocator()); - AtomicBoolean receivedException = new AtomicBoolean(false); - - IntStream.range(0, 2).parallel().forEach((i) -> { - try { - if (i % 2 == 0) { - ((EntryLogManagerBase) el.getEntryLogManager()).createNewLog((long) i); - } else { - el.newCompactionLog(i); - } - } catch (IOException e) { - LOG.error("Received exception while creating newLog", e); - receivedException.set(true); - } - }); - - Assert.assertFalse("There shouldn't be any exceptions while creating newlog", receivedException.get()); - Assert.assertEquals( - "previousAllocatedEntryLogId after 2 times createNewLog is called", 2, - el.getPreviousAllocatedEntryLogId()); - } - - @Test - public void testLastIdCompatibleBetweenDefaultAndDirectEntryLogger() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of - // ledger directories. - conf.setLedgerDirNames(ledgerDirs); - conf.setEntryLogFilePreAllocationEnabled(false); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger el = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerBase entryLogManagerBase = (EntryLogManagerBase) el.getEntryLogManager(); - for (int i = 0; i < 10; i++) { - entryLogManagerBase.createNewLog(i); - } - - Assert.assertEquals(9, el.getPreviousAllocatedEntryLogId()); - - //Mock half ledgerDirs lastId is 3. - for (int i = 0; i < ledgerDirsManager.getAllLedgerDirs().size() / 2; i++) { - File dir = ledgerDirsManager.getAllLedgerDirs().get(i); - LOG.info("Picked this directory: {}", dir); - el.getEntryLoggerAllocator().setLastLogId(dir, 3); - } - - el = new DefaultEntryLogger(conf, ledgerDirsManager); - Assert.assertEquals(9, el.getPreviousAllocatedEntryLogId()); - - //Mock all ledgerDirs lastId is 3. - for (int i = 0; i < ledgerDirsManager.getAllLedgerDirs().size(); i++) { - File dir = ledgerDirsManager.getAllLedgerDirs().get(i); - LOG.info("Picked this directory: {}", dir); - el.getEntryLoggerAllocator().setLastLogId(dir, 3); - } - - el = new DefaultEntryLogger(conf, ledgerDirsManager); - Assert.assertEquals(9, el.getPreviousAllocatedEntryLogId()); - } - - /* - * In this testcase entrylogs for ledgers are tried to create concurrently. - */ - @Test - public void testConcurrentEntryLogCreations() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - // Creating a new configuration with a number of ledger directories. - conf.setLedgerDirNames(ledgerDirs); - // pre-allocation is enabled - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entrylogManager = (EntryLogManagerForEntryLogPerLedger) - entryLogger.getEntryLogManager(); - - int numOfLedgers = 10; - int numOfThreadsForSameLedger = 10; - AtomicInteger createdEntryLogs = new AtomicInteger(0); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch createdLatch = new CountDownLatch(numOfLedgers * numOfThreadsForSameLedger); - - for (long i = 0; i < numOfLedgers; i++) { - for (int j = 0; j < numOfThreadsForSameLedger; j++) { - long ledgerId = i; - new Thread(() -> { - try { - startLatch.await(); - entrylogManager.createNewLog(ledgerId); - createdEntryLogs.incrementAndGet(); - Thread.sleep(2000); - } catch (InterruptedException | IOException e) { - LOG.error("Got exception while trying to createNewLog for Ledger: " + ledgerId, e); - } finally { - createdLatch.countDown(); - } - }).start(); - } - } - - startLatch.countDown(); - createdLatch.await(20, TimeUnit.SECONDS); - Assert.assertEquals("Created EntryLogs", numOfLedgers * numOfThreadsForSameLedger, createdEntryLogs.get()); - Assert.assertEquals("Active currentlogs size", numOfLedgers, entrylogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Rotated entrylogs size", (numOfThreadsForSameLedger - 1) * numOfLedgers, - entrylogManager.getRotatedLogChannels().size()); - /* - * EntryLogFilePreAllocation is Enabled so - * getPreviousAllocatedEntryLogId would be (numOfLedgers * - * numOfThreadsForSameLedger) instead of (numOfLedgers * - * numOfThreadsForSameLedger - 1) - */ - Assert.assertEquals("PreviousAllocatedEntryLogId", numOfLedgers * numOfThreadsForSameLedger, - entryLogger.getPreviousAllocatedEntryLogId()); - } - - /* - * In this testcase metrics of EntryLogManagerForEntryLogPerLedger are - * validated. - */ - @Test - public void testEntryLogManagerMetrics() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(BookKeeperServerStats.ENTRYLOGGER_SCOPE); - int maximumNumberOfActiveEntryLogs = 3; - int entryLogPerLedgerCounterLimitsMultFactor = 2; - - // Creating a new configuration with a number of ledger directories. - conf.setLedgerDirNames(ledgerDirs); - // pre-allocation is enabled - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - conf.setMaximumNumberOfActiveEntryLogs(maximumNumberOfActiveEntryLogs); - conf.setEntryLogPerLedgerCounterLimitsMultFactor(entryLogPerLedgerCounterLimitsMultFactor); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager, null, statsLogger, - UnpooledByteBufAllocator.DEFAULT); - EntryLogManagerForEntryLogPerLedger entrylogManager = (EntryLogManagerForEntryLogPerLedger) entryLogger - .getEntryLogManager(); - // set same thread executor for entryLoggerAllocator's allocatorExecutor - setSameThreadExecutorForEntryLoggerAllocator(entryLogger.getEntryLoggerAllocator()); - - Counter numOfWriteActiveLedgers = statsLogger.getCounter(BookKeeperServerStats.NUM_OF_WRITE_ACTIVE_LEDGERS); - Counter numOfWriteLedgersRemovedCacheExpiry = statsLogger - .getCounter(BookKeeperServerStats.NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_EXPIRY); - Counter numOfWriteLedgersRemovedCacheMaxSize = statsLogger - .getCounter(BookKeeperServerStats.NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_MAXSIZE); - Counter numLedgersHavingMultipleEntrylogs = statsLogger - .getCounter(BookKeeperServerStats.NUM_LEDGERS_HAVING_MULTIPLE_ENTRYLOGS); - TestOpStatsLogger entryLogsPerLedger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(BookKeeperServerStats.ENTRYLOGS_PER_LEDGER); - // initially all the counters should be 0 - Assert.assertEquals("NUM_OF_WRITE_ACTIVE_LEDGERS", 0, numOfWriteActiveLedgers.get().intValue()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_EXPIRY", 0, - numOfWriteLedgersRemovedCacheExpiry.get().intValue()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_MAXSIZE", 0, - numOfWriteLedgersRemovedCacheMaxSize.get().intValue()); - Assert.assertEquals("NUM_LEDGERS_HAVING_MULTIPLE_ENTRYLOGS", 0, - numLedgersHavingMultipleEntrylogs.get().intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 0, entryLogsPerLedger.getSuccessCount()); - - // lid-1 : 3 entrylogs, lid-2 : 2 entrylogs, lid-3 : 1 entrylog - int numOfEntrylogsForLedger1 = 3; - createNewLogs(entrylogManager, 1L, numOfEntrylogsForLedger1); - int numOfEntrylogsForLedger2 = 2; - createNewLogs(entrylogManager, 2L, numOfEntrylogsForLedger2); - createNewLogs(entrylogManager, 3L, 1); - - Assert.assertEquals("NUM_OF_WRITE_ACTIVE_LEDGERS", 3, numOfWriteActiveLedgers.get().intValue()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_EXPIRY", 0, - numOfWriteLedgersRemovedCacheExpiry.get().intValue()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_MAXSIZE", 0, - numOfWriteLedgersRemovedCacheMaxSize.get().intValue()); - Assert.assertEquals("NUM_LEDGERS_HAVING_MULTIPLE_ENTRYLOGS", 2, - numLedgersHavingMultipleEntrylogs.get().intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 0, entryLogsPerLedger.getSuccessCount()); - - /* - * since entrylog for lid-4 is created and entrylogmap cachesize is 3, - * lid-1 will be removed from entrylogmap cache - */ - createNewLogs(entrylogManager, 4L, 1); - Assert.assertEquals("NUM_OF_WRITE_ACTIVE_LEDGERS", maximumNumberOfActiveEntryLogs, - numOfWriteActiveLedgers.get().intValue()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_MAXSIZE", 1, - numOfWriteLedgersRemovedCacheMaxSize.get().intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 0, entryLogsPerLedger.getSuccessCount()); - - /* - * entrylog for lid-5, lid-6, lid-7 are created. Since - * maximumNumberOfActiveEntryLogs = 3 and - * entryLogPerLedgerCounterLimitsMultFactor = 2, when the entrylog for - * lid-7 is created, count of lid-1 should be removed from countermap. - */ - createNewLogs(entrylogManager, 5L, 1); - createNewLogs(entrylogManager, 6L, 1); - createNewLogs(entrylogManager, 7L, 1); - Assert.assertEquals("NUM_OF_WRITE_ACTIVE_LEDGERS", maximumNumberOfActiveEntryLogs, - numOfWriteActiveLedgers.get().intValue()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_MAXSIZE", 4, - numOfWriteLedgersRemovedCacheMaxSize.get().intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 1, entryLogsPerLedger.getSuccessCount()); - Assert.assertTrue("ENTRYLOGS_PER_LEDGER average value", - Double.compare(numOfEntrylogsForLedger1, entryLogsPerLedger.getSuccessAverage()) == 0); - - /* - * entrylog for new lid-8 is created so one more entry from countermap - * should be removed. - */ - createNewLogs(entrylogManager, 8L, 4); - Assert.assertEquals("NUM_OF_WRITE_ACTIVE_LEDGERS", maximumNumberOfActiveEntryLogs, - numOfWriteActiveLedgers.get().intValue()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_MAXSIZE", 5, - numOfWriteLedgersRemovedCacheMaxSize.get().intValue()); - Assert.assertEquals("NUM_LEDGERS_HAVING_MULTIPLE_ENTRYLOGS", 3, - numLedgersHavingMultipleEntrylogs.get().intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 2, entryLogsPerLedger.getSuccessCount()); - Assert.assertTrue("ENTRYLOGS_PER_LEDGER average value", - Double.compare((numOfEntrylogsForLedger1 + numOfEntrylogsForLedger2) / 2.0, - entryLogsPerLedger.getSuccessAverage()) == 0); - - /* - * lid-3 is still in countermap. So when new entrylogs are created for - * lid-3, no new entry from counter should be removed. so - * entryLogsPerLedger.getSuccessCount() should be still old value. Also, - * since lid-3 is still in countermap, these new 4 entrylogs should be - * added to previous value 1 and hence the EntryLogsPerLedger for ledger - * - 3l should be updated to 5. - */ - createNewLogs(entrylogManager, 3L, 4); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_MAXSIZE", 6, - numOfWriteLedgersRemovedCacheMaxSize.get().intValue()); - Assert.assertEquals("NUM_LEDGERS_HAVING_MULTIPLE_ENTRYLOGS", 4, - numLedgersHavingMultipleEntrylogs.get().intValue()); - Assert.assertEquals("Numofentrylogs for ledger: 3l", 5, - entrylogManager.entryLogsPerLedgerCounter.getCounterMap().get(3L).intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 2, entryLogsPerLedger.getSuccessCount()); - } - - /* - * In this testcase metrics of EntryLogManagerForEntryLogPerLedger are - * validated. - */ - @Test - public void testEntryLogManagerMetricsFromExpiryAspect() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(BookKeeperServerStats.ENTRYLOGGER_SCOPE); - - int entrylogMapAccessExpiryTimeInSeconds = 1; - int entryLogPerLedgerCounterLimitsMultFactor = 2; - - // Creating a new configuration with a number of ledger directories. - conf.setLedgerDirNames(ledgerDirs); - // pre-allocation is enabled - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - conf.setEntrylogMapAccessExpiryTimeInSeconds(entrylogMapAccessExpiryTimeInSeconds); - conf.setEntryLogPerLedgerCounterLimitsMultFactor(entryLogPerLedgerCounterLimitsMultFactor); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager, null, statsLogger, - UnpooledByteBufAllocator.DEFAULT); - EntryLogManagerForEntryLogPerLedger entrylogManager = (EntryLogManagerForEntryLogPerLedger) entryLogger - .getEntryLogManager(); - // set same thread executor for entryLoggerAllocator's allocatorExecutor - setSameThreadExecutorForEntryLoggerAllocator(entryLogger.getEntryLoggerAllocator()); - - Counter numOfWriteLedgersRemovedCacheExpiry = statsLogger - .getCounter(BookKeeperServerStats.NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_EXPIRY); - TestOpStatsLogger entryLogsPerLedger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(BookKeeperServerStats.ENTRYLOGS_PER_LEDGER); - - int numOfEntrylogsForLedger1 = 3; - createNewLogs(entrylogManager, 1L, numOfEntrylogsForLedger1); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 0, entryLogsPerLedger.getSuccessCount()); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_EXPIRY", 0, - numOfWriteLedgersRemovedCacheExpiry.get().intValue()); - - Thread.sleep(entrylogMapAccessExpiryTimeInSeconds * 1000 + 100); - entrylogManager.doEntryLogMapCleanup(); - entrylogManager.entryLogsPerLedgerCounter.doCounterMapCleanup(); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_EXPIRY", 1, - numOfWriteLedgersRemovedCacheExpiry.get().intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 0, entryLogsPerLedger.getSuccessCount()); - - Thread.sleep(entrylogMapAccessExpiryTimeInSeconds * 1000 + 100); - entrylogManager.doEntryLogMapCleanup(); - entrylogManager.entryLogsPerLedgerCounter.doCounterMapCleanup(); - Assert.assertEquals("NUM_OF_WRITE_LEDGERS_REMOVED_CACHE_EXPIRY", 1, - numOfWriteLedgersRemovedCacheExpiry.get().intValue()); - Assert.assertEquals("ENTRYLOGS_PER_LEDGER SuccessCount", 1, entryLogsPerLedger.getSuccessCount()); - Assert.assertTrue("ENTRYLOGS_PER_LEDGER average value", - Double.compare(numOfEntrylogsForLedger1, entryLogsPerLedger.getSuccessAverage()) == 0); - } - - private static void createNewLogs(EntryLogManagerForEntryLogPerLedger entrylogManager, long ledgerId, - int numOfTimes) throws IOException { - for (int i = 0; i < numOfTimes; i++) { - entrylogManager.createNewLog(ledgerId); - } - } - - @Test - public void testLockConsistency() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - - conf.setLedgerDirNames(ledgerDirs); - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setEntryLogPerLedgerEnabled(true); - conf.setMaximumNumberOfActiveEntryLogs(5); - - CountDownLatch latch = new CountDownLatch(1); - AtomicInteger count = new AtomicInteger(0); - - /* - * Inject wait operation in 'getWritableLedgerDirsForNewLog' method of - * ledgerDirsManager. getWritableLedgerDirsForNewLog will be called when - * entryLogManager.createNewLog is called. - */ - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())) { - /* - * getWritableLedgerDirsForNewLog is called for the first time, it - * will await on 'latch' latch before calling super - * getWritableLedgerDirsForNewLog. - */ - @Override - public List getWritableLedgerDirsForNewLog() throws NoWritableLedgerDirException { - if (count.incrementAndGet() == 1) { - try { - latch.await(); - } catch (InterruptedException e) { - LOG.error("Got InterruptedException while awaiting for latch countdown", e); - } - } - return super.getWritableLedgerDirsForNewLog(); - } - }; - - DefaultEntryLogger el = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) el - .getEntryLogManager(); - - long firstLedgerId = 100L; - AtomicBoolean newLogCreated = new AtomicBoolean(false); - - Assert.assertFalse("EntryLogManager cacheMap should not contain entry for firstLedgerId", - entryLogManager.getCacheAsMap().containsKey(firstLedgerId)); - Assert.assertEquals("Value of the count should be 0", 0, count.get()); - /* - * In a new thread, create newlog for 'firstLedgerId' and then set - * 'newLogCreated' to true. Since this is the first createNewLog call, - * it is going to be blocked untill latch is countdowned to 0. - */ - new Thread() { - @Override - public void run() { - try { - entryLogManager.createNewLog(firstLedgerId); - newLogCreated.set(true); - } catch (IOException e) { - LOG.error("Got IOException while creating new log", e); - } - } - }.start(); - - /* - * Wait until entry for 'firstLedgerId' is created in cacheMap. It will - * be created because in the other thread createNewLog is called. - */ - while (!entryLogManager.getCacheAsMap().containsKey(firstLedgerId)) { - Thread.sleep(200); - } - Lock firstLedgersLock = entryLogManager.getLock(firstLedgerId); - - /* - * since 'latch' is not counteddown, newlog should not be created even - * after waitign for 2 secs. - */ - Thread.sleep(2000); - Assert.assertFalse("New log shouldn't have created", newLogCreated.get()); - - /* - * create MaximumNumberOfActiveEntryLogs of entrylogs and do cache - * cleanup, so that the earliest entry from cache will be removed. - */ - for (int i = 1; i <= conf.getMaximumNumberOfActiveEntryLogs(); i++) { - entryLogManager.createNewLog(firstLedgerId + i); - } - entryLogManager.doEntryLogMapCleanup(); - Assert.assertFalse("Entry for that ledger shouldn't be there", - entryLogManager.getCacheAsMap().containsKey(firstLedgerId)); - - /* - * now countdown the latch, so that the other thread can make progress - * with createNewLog and since this entry is evicted from cache, - * entrylog of the newly created entrylog will be added to - * rotatedentrylogs. - */ - latch.countDown(); - while (!newLogCreated.get()) { - Thread.sleep(200); - } - while (entryLogManager.getRotatedLogChannels().size() < 1) { - Thread.sleep(200); - } - - /* - * Entry for 'firstLedgerId' is removed from cache, but even in this - * case when we get lock for the 'firstLedgerId' it should be the same - * as we got earlier. - */ - Lock lockForThatLedgerAfterRemoval = entryLogManager.getLock(firstLedgerId); - Assert.assertEquals("For a given ledger lock should be the same before and after removal", firstLedgersLock, - lockForThatLedgerAfterRemoval); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/DefaultEntryLogTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/DefaultEntryLogTest.java deleted file mode 100644 index 3048ef33a8c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/DefaultEntryLogTest.java +++ /dev/null @@ -1,1927 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.assertEntryEquals; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.makeEntry; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Sets; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.util.ReferenceCountUtil; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLongArray; -import java.util.concurrent.locks.Lock; -import org.apache.bookkeeper.bookie.DefaultEntryLogger.BufferedLogChannel; -import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.bookkeeper.util.collections.ConcurrentLongLongHashMap; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.FixMethodOrder; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runners.MethodSorters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests for EntryLog. - */ -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class DefaultEntryLogTest { - private static final Logger LOG = LoggerFactory.getLogger(DefaultEntryLogTest.class); - - final List tempDirs = new ArrayList(); - final Random rand = new Random(); - - File createTempDir(String prefix, String suffix) throws IOException { - File dir = IOUtils.createTempDir(prefix, suffix); - tempDirs.add(dir); - return dir; - } - - private File rootDir; - private File curDir; - private ServerConfiguration conf; - private LedgerDirsManager dirsMgr; - private DefaultEntryLogger entryLogger; - - @Before - public void setUp() throws Exception { - this.rootDir = createTempDir("bkTest", ".dir"); - this.curDir = BookieImpl.getCurrentDirectory(rootDir); - BookieImpl.checkDirectoryStructure(curDir); - this.conf = TestBKConfiguration.newServerConfiguration(); - this.dirsMgr = new LedgerDirsManager( - conf, - new File[] { rootDir }, - new DiskChecker( - conf.getDiskUsageThreshold(), - conf.getDiskUsageWarnThreshold())); - this.entryLogger = new DefaultEntryLogger(conf, dirsMgr); - } - - @After - public void tearDown() throws Exception { - if (null != this.entryLogger) { - entryLogger.close(); - } - - for (File dir : tempDirs) { - FileUtils.deleteDirectory(dir); - } - tempDirs.clear(); - } - - @Test - public void testDeferCreateNewLog() throws Exception { - entryLogger.close(); - - // mark `curDir` as filled - this.conf.setMinUsableSizeForEntryLogCreation(1); - this.dirsMgr = new LedgerDirsManager( - conf, - new File[] { rootDir }, - new DiskChecker( - conf.getDiskUsageThreshold(), - conf.getDiskUsageWarnThreshold())); - this.dirsMgr.addToFilledDirs(curDir); - - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - EntryLogManagerForSingleEntryLog entryLogManager = - (EntryLogManagerForSingleEntryLog) entryLogger.getEntryLogManager(); - assertEquals(DefaultEntryLogger.UNINITIALIZED_LOG_ID, entryLogManager.getCurrentLogId()); - - // add the first entry will trigger file creation - entryLogger.addEntry(1L, generateEntry(1, 1).nioBuffer()); - assertEquals(0L, entryLogManager.getCurrentLogId()); - } - - @Test - public void testEntryLogIsSealedWithPerLedgerDisabled() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogPerLedgerEnabled(false); - conf.setEntryLogFilePreAllocationEnabled(true); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsProvider.TestStatsLogger statsLogger = - statsProvider.getStatsLogger(BookKeeperServerStats.ENTRYLOGGER_SCOPE); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, dirsMgr, null, statsLogger, - UnpooledByteBufAllocator.DEFAULT); - EntryLogManagerBase entrylogManager = (EntryLogManagerBase) entryLogger.getEntryLogManager(); - entrylogManager.createNewLog(0); - BufferedReadChannel channel = entryLogger.getChannelForLogId(0); - assertFalse(channel.sealed); - entrylogManager.createNewLog(1); - channel = entryLogger.getChannelForLogId(0); - assertFalse(channel.sealed); - entrylogManager.createNewLog(2); - channel = entryLogger.getChannelForLogId(1); - assertTrue(channel.sealed); - } - - @Test - public void testEntryLogIsSealedWithPerLedgerEnabled() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - //If entryLogPerLedgerEnabled is true, the buffer channel sealed flag always false. - conf.setEntryLogPerLedgerEnabled(true); - conf.setEntryLogFilePreAllocationEnabled(true); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsProvider.TestStatsLogger statsLogger = - statsProvider.getStatsLogger(BookKeeperServerStats.ENTRYLOGGER_SCOPE); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, dirsMgr, null, statsLogger, - UnpooledByteBufAllocator.DEFAULT); - EntryLogManagerBase entrylogManager = (EntryLogManagerBase) entryLogger.getEntryLogManager(); - entrylogManager.createNewLog(0); - BufferedReadChannel channel = entryLogger.getChannelForLogId(0); - assertFalse(channel.sealed); - entrylogManager.createNewLog(1); - channel = entryLogger.getChannelForLogId(0); - assertFalse(channel.sealed); - entrylogManager.createNewLog(2); - channel = entryLogger.getChannelForLogId(1); - assertFalse(channel.sealed); - } - - @Test - public void testDeferCreateNewLogWithoutEnoughDiskSpaces() throws Exception { - entryLogger.close(); - - // mark `curDir` as filled - this.conf.setMinUsableSizeForEntryLogCreation(Long.MAX_VALUE); - this.dirsMgr = new LedgerDirsManager( - conf, - new File[] { rootDir }, - new DiskChecker( - conf.getDiskUsageThreshold(), - conf.getDiskUsageWarnThreshold())); - this.dirsMgr.addToFilledDirs(curDir); - - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - EntryLogManagerForSingleEntryLog entryLogManager = - (EntryLogManagerForSingleEntryLog) entryLogger.getEntryLogManager(); - assertEquals(DefaultEntryLogger.UNINITIALIZED_LOG_ID, entryLogManager.getCurrentLogId()); - - // add the first entry will trigger file creation - try { - entryLogger.addEntry(1L, generateEntry(1, 1).nioBuffer()); - fail("Should fail to append entry if there is no enough reserved space left"); - } catch (NoWritableLedgerDirException e) { - assertEquals(DefaultEntryLogger.UNINITIALIZED_LOG_ID, entryLogManager.getCurrentLogId()); - } - } - - @Test - public void testCorruptEntryLog() throws Exception { - // create some entries - entryLogger.addEntry(1L, generateEntry(1, 1).nioBuffer()); - entryLogger.addEntry(3L, generateEntry(3, 1).nioBuffer()); - entryLogger.addEntry(2L, generateEntry(2, 1).nioBuffer()); - entryLogger.flush(); - entryLogger.close(); - // now lets truncate the file to corrupt the last entry, which simulates a partial write - File f = new File(curDir, "0.log"); - RandomAccessFile raf = new RandomAccessFile(f, "rw"); - raf.setLength(raf.length() - 10); - raf.close(); - // now see which ledgers are in the log - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(0L); - String metaString = meta.toString(); - assertEquals(metaString, - "{totalSize = 60, remainingSize = 60, ledgersMap = ConcurrentLongLongHashMap{1 => 30, 3 => 30}}"); - LOG.info("Extracted Meta From Entry Log {}", meta); - assertTrue(meta.getLedgersMap().containsKey(1L)); - assertFalse(meta.getLedgersMap().containsKey(2L)); - assertTrue(meta.getLedgersMap().containsKey(3L)); - } - - private static ByteBuf generateEntry(long ledger, long entry) { - byte[] data = generateDataString(ledger, entry).getBytes(); - ByteBuf bb = Unpooled.buffer(8 + 8 + data.length); - bb.writeLong(ledger); - bb.writeLong(entry); - bb.writeBytes(data); - return bb; - } - - private ByteBuf generateEntry(long ledger, long entry, int length) { - ByteBuf bb = Unpooled.buffer(length); - bb.writeLong(ledger); - bb.writeLong(entry); - byte[] randbyteArray = new byte[length - 8 - 8]; - rand.nextBytes(randbyteArray); - bb.writeBytes(randbyteArray); - return bb; - } - - private static String generateDataString(long ledger, long entry) { - return ("ledger-" + ledger + "-" + entry); - } - - @Test - public void testMissingLogId() throws Exception { - // create some entries - int numLogs = 3; - int numEntries = 10; - long[][] positions = new long[2 * numLogs][]; - for (int i = 0; i < numLogs; i++) { - positions[i] = new long[numEntries]; - - DefaultEntryLogger logger = new DefaultEntryLogger(conf, dirsMgr); - for (int j = 0; j < numEntries; j++) { - positions[i][j] = logger.addEntry((long) i, generateEntry(i, j).nioBuffer()); - } - logger.flush(); - logger.close(); - } - // delete last log id - File lastLogId = new File(curDir, "lastId"); - lastLogId.delete(); - - // write another entries - for (int i = numLogs; i < 2 * numLogs; i++) { - positions[i] = new long[numEntries]; - - DefaultEntryLogger logger = new DefaultEntryLogger(conf, dirsMgr); - for (int j = 0; j < numEntries; j++) { - positions[i][j] = logger.addEntry((long) i, generateEntry(i, j).nioBuffer()); - } - logger.flush(); - logger.close(); - } - - DefaultEntryLogger newLogger = new DefaultEntryLogger(conf, dirsMgr); - for (int i = 0; i < (2 * numLogs + 1); i++) { - File logFile = new File(curDir, Long.toHexString(i) + ".log"); - assertTrue(logFile.exists()); - } - for (int i = 0; i < 2 * numLogs; i++) { - for (int j = 0; j < numEntries; j++) { - String expectedValue = "ledger-" + i + "-" + j; - ByteBuf value = newLogger.readEntry(i, j, positions[i][j]); - long ledgerId = value.readLong(); - long entryId = value.readLong(); - byte[] data = new byte[value.readableBytes()]; - value.readBytes(data); - value.release(); - assertEquals(i, ledgerId); - assertEquals(j, entryId); - assertEquals(expectedValue, new String(data)); - } - } - } - - /** - * Test that EntryLogger Should fail with FNFE, if entry logger directories does not exist. - */ - @Ignore // no longer valid as LedgerDirsManager creates the directory as needed - public void testEntryLoggerShouldThrowFNFEIfDirectoriesDoesNotExist() - throws Exception { - File tmpDir = createTempDir("bkTest", ".dir"); - DefaultEntryLogger entryLogger = null; - try { - entryLogger = new DefaultEntryLogger(conf, new LedgerDirsManager(conf, new File[] { tmpDir }, - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()))); - fail("Expecting FileNotFoundException"); - } catch (FileNotFoundException e) { - assertEquals("Entry log directory '" + tmpDir + "/current' does not exist", e - .getLocalizedMessage()); - } finally { - if (entryLogger != null) { - entryLogger.close(); - } - } - } - - /** - * Test to verify the DiskFull during addEntry. - */ - @Test - public void testAddEntryFailureOnDiskFull() throws Exception { - File ledgerDir1 = createTempDir("bkTest", ".dir"); - File ledgerDir2 = createTempDir("bkTest", ".dir"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - conf.setJournalDirName(ledgerDir1.toString()); - conf.setLedgerDirNames(new String[] { ledgerDir1.getAbsolutePath(), - ledgerDir2.getAbsolutePath() }); - BookieImpl bookie = new TestBookieImpl(conf); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, - bookie.getLedgerDirsManager()); - InterleavedLedgerStorage ledgerStorage = - ((InterleavedLedgerStorage) bookie.ledgerStorage.getUnderlyingLedgerStorage()); - ledgerStorage.entryLogger = entryLogger; - // Create ledgers - ledgerStorage.setMasterKey(1, "key".getBytes()); - ledgerStorage.setMasterKey(2, "key".getBytes()); - ledgerStorage.setMasterKey(3, "key".getBytes()); - // Add entries - ledgerStorage.addEntry(generateEntry(1, 1)); - ledgerStorage.addEntry(generateEntry(2, 1)); - // Add entry with disk full failure simulation - bookie.getLedgerDirsManager().addToFilledDirs(((EntryLogManagerBase) entryLogger.getEntryLogManager()) - .getCurrentLogForLedger(DefaultEntryLogger.UNASSIGNED_LEDGERID).getLogFile().getParentFile()); - ledgerStorage.addEntry(generateEntry(3, 1)); - // Verify written entries - Assert.assertTrue(0 == generateEntry(1, 1).compareTo(ledgerStorage.getEntry(1, 1))); - Assert.assertTrue(0 == generateEntry(2, 1).compareTo(ledgerStorage.getEntry(2, 1))); - Assert.assertTrue(0 == generateEntry(3, 1).compareTo(ledgerStorage.getEntry(3, 1))); - } - - /** - * Explicitly try to recover using the ledgers map index at the end of the entry log. - */ - @Test - public void testRecoverFromLedgersMap() throws Exception { - // create some entries - entryLogger.addEntry(1L, generateEntry(1, 1).nioBuffer()); - entryLogger.addEntry(3L, generateEntry(3, 1).nioBuffer()); - entryLogger.addEntry(2L, generateEntry(2, 1).nioBuffer()); - entryLogger.addEntry(1L, generateEntry(1, 2).nioBuffer()); - - EntryLogManagerBase entryLogManager = (EntryLogManagerBase) entryLogger.getEntryLogManager(); - entryLogManager.createNewLog(DefaultEntryLogger.UNASSIGNED_LEDGERID); - entryLogManager.flushRotatedLogs(); - - EntryLogMetadata meta = entryLogger.extractEntryLogMetadataFromIndex(0L); - LOG.info("Extracted Meta From Entry Log {}", meta); - assertEquals(60, meta.getLedgersMap().get(1L)); - assertEquals(30, meta.getLedgersMap().get(2L)); - assertEquals(30, meta.getLedgersMap().get(3L)); - assertFalse(meta.getLedgersMap().containsKey(4L)); - assertEquals(120, meta.getTotalSize()); - assertEquals(120, meta.getRemainingSize()); - } - - /** - * Explicitly try to recover using the ledgers map index at the end of the entry log. - */ - @Test - public void testRecoverFromLedgersMapOnV0EntryLog() throws Exception { - // create some entries - entryLogger.addEntry(1L, generateEntry(1, 1).nioBuffer()); - entryLogger.addEntry(3L, generateEntry(3, 1).nioBuffer()); - entryLogger.addEntry(2L, generateEntry(2, 1).nioBuffer()); - entryLogger.addEntry(1L, generateEntry(1, 2).nioBuffer()); - ((EntryLogManagerBase) entryLogger.getEntryLogManager()).createNewLog(DefaultEntryLogger.UNASSIGNED_LEDGERID); - entryLogger.close(); - - // Rewrite the entry log header to be on V0 format - File f = new File(curDir, "0.log"); - RandomAccessFile raf = new RandomAccessFile(f, "rw"); - raf.seek(DefaultEntryLogger.HEADER_VERSION_POSITION); - // Write zeros to indicate V0 + no ledgers map info - raf.write(new byte[4 + 8]); - raf.close(); - - // now see which ledgers are in the log - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - - try { - entryLogger.extractEntryLogMetadataFromIndex(0L); - fail("Should not be possible to recover from ledgers map index"); - } catch (IOException e) { - // Ok - } - - // Public method should succeed by falling back to scanning the file - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(0L); - LOG.info("Extracted Meta From Entry Log {}", meta); - assertEquals(60, meta.getLedgersMap().get(1L)); - assertEquals(30, meta.getLedgersMap().get(2L)); - assertEquals(30, meta.getLedgersMap().get(3L)); - assertFalse(meta.getLedgersMap().containsKey(4L)); - assertEquals(120, meta.getTotalSize()); - assertEquals(120, meta.getRemainingSize()); - } - - /** - * Test pre-allocate for entry log in EntryLoggerAllocator. - * @throws Exception - */ - @Test - public void testPreAllocateLog() throws Exception { - entryLogger.close(); - - // enable pre-allocation case - conf.setEntryLogFilePreAllocationEnabled(true); - - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - // create a logger whose initialization phase allocating a new entry log - ((EntryLogManagerBase) entryLogger.getEntryLogManager()).createNewLog(DefaultEntryLogger.UNASSIGNED_LEDGERID); - assertNotNull(entryLogger.getEntryLoggerAllocator().getPreallocationFuture()); - - entryLogger.addEntry(1L, generateEntry(1, 1).nioBuffer()); - // the Future is not null all the time - assertNotNull(entryLogger.getEntryLoggerAllocator().getPreallocationFuture()); - entryLogger.close(); - - // disable pre-allocation case - conf.setEntryLogFilePreAllocationEnabled(false); - // create a logger - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - assertNull(entryLogger.getEntryLoggerAllocator().getPreallocationFuture()); - - entryLogger.addEntry(2L, generateEntry(1, 1).nioBuffer()); - - // the Future is null all the time - assertNull(entryLogger.getEntryLoggerAllocator().getPreallocationFuture()); - } - - /** - * Test the getEntryLogsSet() method. - */ - @Test - public void testGetEntryLogsSet() throws Exception { - // create some entries - EntryLogManagerBase entryLogManagerBase = ((EntryLogManagerBase) entryLogger.getEntryLogManager()); - assertEquals(Sets.newHashSet(), entryLogger.getEntryLogsSet()); - - entryLogManagerBase.createNewLog(DefaultEntryLogger.UNASSIGNED_LEDGERID); - entryLogManagerBase.flushRotatedLogs(); - - Thread.sleep(2000); - assertEquals(Sets.newHashSet(0L, 1L), entryLogger.getEntryLogsSet()); - - entryLogManagerBase.createNewLog(DefaultEntryLogger.UNASSIGNED_LEDGERID); - entryLogManagerBase.flushRotatedLogs(); - - assertEquals(Sets.newHashSet(0L, 1L, 2L), entryLogger.getEntryLogsSet()); - } - - /** - * In this testcase, entryLogger flush and entryLogger addEntry (which would - * call createNewLog) are called concurrently. Since entryLogger flush - * method flushes both currentlog and rotatedlogs, it is expected all the - * currentLog and rotatedLogs are supposed to be flush and forcewritten. - * - * @throws Exception - */ - @Test - public void testFlushOrder() throws Exception { - entryLogger.close(); - - int logSizeLimit = 256 * 1024; - conf.setEntryLogPerLedgerEnabled(false); - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setFlushIntervalInBytes(0); - conf.setEntryLogSizeLimit(logSizeLimit); - - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - EntryLogManagerBase entryLogManager = (EntryLogManagerBase) entryLogger.getEntryLogManager(); - AtomicBoolean exceptionHappened = new AtomicBoolean(false); - - CyclicBarrier barrier = new CyclicBarrier(2); - List rotatedLogChannels; - BufferedLogChannel currentActiveChannel; - - exceptionHappened.set(false); - - /* - * higher the number of rotated logs, it would be easier to reproduce - * the issue regarding flush order - */ - addEntriesAndRotateLogs(entryLogger, 30); - - rotatedLogChannels = new LinkedList(entryLogManager.getRotatedLogChannels()); - currentActiveChannel = entryLogManager.getCurrentLogForLedger(DefaultEntryLogger.UNASSIGNED_LEDGERID); - long currentActiveChannelUnpersistedBytes = currentActiveChannel.getUnpersistedBytes(); - - Thread flushThread = new Thread(new Runnable() { - @Override - public void run() { - try { - barrier.await(); - entryLogger.flush(); - } catch (InterruptedException | BrokenBarrierException | IOException e) { - LOG.error("Exception happened for entryLogger.flush", e); - exceptionHappened.set(true); - } - } - }); - - Thread createdNewLogThread = new Thread(new Runnable() { - @Override - public void run() { - try { - barrier.await(); - /* - * here we are adding entry of size logSizeLimit with - * rolllog=true, so it would create a new entrylog. - */ - entryLogger.addEntry(123, generateEntry(123, 456, logSizeLimit)); - } catch (InterruptedException | BrokenBarrierException | IOException e) { - LOG.error("Exception happened for entryLogManager.createNewLog", e); - exceptionHappened.set(true); - } - } - }); - - /* - * concurrently entryLogger flush and entryLogger addEntry (which would - * call createNewLog) would be called from different threads. - */ - flushThread.start(); - createdNewLogThread.start(); - flushThread.join(); - createdNewLogThread.join(); - - Assert.assertFalse("Exception happened in one of the operation", exceptionHappened.get()); - - if (conf.getFlushIntervalInBytes() > 0) { - /* - * if flush of the previous current channel is called then the - * unpersistedBytes should be less than what it was before, actually - * it would be close to zero (but when new log is created with - * addEntry call, ledgers map will be appended at the end of entry - * log) - */ - Assert.assertTrue( - "previous currentChannel unpersistedBytes should be less than " - + currentActiveChannelUnpersistedBytes - + ", but it is actually " + currentActiveChannel.getUnpersistedBytes(), - currentActiveChannel.getUnpersistedBytes() < currentActiveChannelUnpersistedBytes); - } - for (BufferedLogChannel rotatedLogChannel : rotatedLogChannels) { - Assert.assertEquals("previous rotated entrylog should be flushandforcewritten", 0, - rotatedLogChannel.getUnpersistedBytes()); - } - } - - void addEntriesAndRotateLogs(DefaultEntryLogger entryLogger, int numOfRotations) - throws IOException { - EntryLogManagerBase entryLogManager = (EntryLogManagerBase) entryLogger.getEntryLogManager(); - entryLogManager.setCurrentLogForLedgerAndAddToRotate(DefaultEntryLogger.UNASSIGNED_LEDGERID, null); - for (int i = 0; i < numOfRotations; i++) { - addEntries(entryLogger, 10); - entryLogManager.setCurrentLogForLedgerAndAddToRotate(DefaultEntryLogger.UNASSIGNED_LEDGERID, null); - } - addEntries(entryLogger, 10); - } - - void addEntries(DefaultEntryLogger entryLogger, int noOfEntries) throws IOException { - for (int j = 0; j < noOfEntries; j++) { - int ledgerId = Math.abs(rand.nextInt()); - int entryId = Math.abs(rand.nextInt()); - entryLogger.addEntry(ledgerId, generateEntry(ledgerId, entryId).nioBuffer()); - } - } - - static class LedgerStorageWriteTask implements Callable { - long ledgerId; - int entryId; - LedgerStorage ledgerStorage; - - LedgerStorageWriteTask(long ledgerId, int entryId, LedgerStorage ledgerStorage) { - this.ledgerId = ledgerId; - this.entryId = entryId; - this.ledgerStorage = ledgerStorage; - } - - @Override - public Boolean call() throws IOException, BookieException { - try { - ledgerStorage.addEntry(generateEntry(ledgerId, entryId)); - } catch (IOException e) { - LOG.error("Got Exception for AddEntry call. LedgerId: " + ledgerId + " entryId: " + entryId, e); - throw new IOException("Got Exception for AddEntry call. LedgerId: " + ledgerId + " entryId: " + entryId, - e); - } - return true; - } - } - - static class LedgerStorageFlushTask implements Callable { - LedgerStorage ledgerStorage; - - LedgerStorageFlushTask(LedgerStorage ledgerStorage) { - this.ledgerStorage = ledgerStorage; - } - - @Override - public Boolean call() throws IOException { - try { - ledgerStorage.flush(); - } catch (IOException e) { - LOG.error("Got Exception for flush call", e); - throw new IOException("Got Exception for Flush call", e); - } - return true; - } - } - - static class LedgerStorageReadTask implements Callable { - long ledgerId; - int entryId; - LedgerStorage ledgerStorage; - - LedgerStorageReadTask(long ledgerId, int entryId, LedgerStorage ledgerStorage) { - this.ledgerId = ledgerId; - this.entryId = entryId; - this.ledgerStorage = ledgerStorage; - } - - @Override - public Boolean call() throws IOException, BookieException { - try { - ByteBuf expectedByteBuf = generateEntry(ledgerId, entryId); - ByteBuf actualByteBuf = ledgerStorage.getEntry(ledgerId, entryId); - if (!expectedByteBuf.equals(actualByteBuf)) { - LOG.error("Expected Entry: {} Actual Entry: {}", expectedByteBuf.toString(Charset.defaultCharset()), - actualByteBuf.toString(Charset.defaultCharset())); - throw new IOException("Expected Entry: " + expectedByteBuf.toString(Charset.defaultCharset()) - + " Actual Entry: " + actualByteBuf.toString(Charset.defaultCharset())); - } - } catch (IOException e) { - LOG.error("Got Exception for GetEntry call. LedgerId: " + ledgerId + " entryId: " + entryId, e); - throw new IOException("Got Exception for GetEntry call. LedgerId: " + ledgerId + " entryId: " + entryId, - e); - } - return true; - } - } - - /** - * test concurrent write operations and then concurrent read operations - * using InterleavedLedgerStorage. - */ - @FlakyTest(value = "https://github.com/apache/bookkeeper/issues/1516") - public void testConcurrentWriteAndReadCallsOfInterleavedLedgerStorage() throws Exception { - testConcurrentWriteAndReadCalls(InterleavedLedgerStorage.class.getName(), false); - } - - /** - * test concurrent write operations and then concurrent read operations - * using InterleavedLedgerStorage with EntryLogPerLedger enabled. - */ - @FlakyTest(value = "https://github.com/apache/bookkeeper/issues/1516") - public void testConcurrentWriteAndReadCallsOfInterleavedLedgerStorageWithELPLEnabled() throws Exception { - testConcurrentWriteAndReadCalls(InterleavedLedgerStorage.class.getName(), true); - } - - /** - * test concurrent write operations and then concurrent read operations - * using SortedLedgerStorage. - */ - @FlakyTest(value = "https://github.com/apache/bookkeeper/issues/1516") - public void testConcurrentWriteAndReadCallsOfSortedLedgerStorage() throws Exception { - testConcurrentWriteAndReadCalls(SortedLedgerStorage.class.getName(), false); - } - - /** - * test concurrent write operations and then concurrent read operations - * using SortedLedgerStorage with EntryLogPerLedger enabled. - */ - @FlakyTest(value = "https://github.com/apache/bookkeeper/issues/1516") - public void testConcurrentWriteAndReadCallsOfSortedLedgerStorageWithELPLEnabled() throws Exception { - testConcurrentWriteAndReadCalls(SortedLedgerStorage.class.getName(), true); - } - - public void testConcurrentWriteAndReadCalls(String ledgerStorageClass, boolean entryLogPerLedgerEnabled) - throws Exception { - File ledgerDir = createTempDir("bkTest", ".dir"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(ledgerDir.toString()); - conf.setLedgerDirNames(new String[] { ledgerDir.getAbsolutePath()}); - conf.setLedgerStorageClass(ledgerStorageClass); - conf.setEntryLogPerLedgerEnabled(entryLogPerLedgerEnabled); - BookieImpl bookie = new TestBookieImpl(conf); - CompactableLedgerStorage ledgerStorage = (CompactableLedgerStorage) bookie.ledgerStorage; - Random rand = new Random(0); - - if (ledgerStorageClass.equals(SortedLedgerStorage.class.getName())) { - Assert.assertEquals("LedgerStorage Class", SortedLedgerStorage.class, ledgerStorage.getClass()); - if (entryLogPerLedgerEnabled) { - Assert.assertEquals("MemTable Class", EntryMemTableWithParallelFlusher.class, - ((SortedLedgerStorage) ledgerStorage).memTable.getClass()); - } else { - Assert.assertEquals("MemTable Class", EntryMemTable.class, - ((SortedLedgerStorage) ledgerStorage).memTable.getClass()); - } - } - - int numOfLedgers = 70; - int numEntries = 1500; - // Create ledgers - for (int i = 0; i < numOfLedgers; i++) { - ledgerStorage.setMasterKey(i, "key".getBytes()); - } - - ExecutorService executor = Executors.newFixedThreadPool(10); - List> writeAndFlushTasks = new ArrayList>(); - for (int j = 0; j < numEntries; j++) { - for (int i = 0; i < numOfLedgers; i++) { - writeAndFlushTasks.add(new LedgerStorageWriteTask(i, j, ledgerStorage)); - } - } - - /* - * add some flush tasks to the list of writetasks list. - */ - for (int i = 0; i < (numOfLedgers * numEntries) / 500; i++) { - writeAndFlushTasks.add(rand.nextInt(writeAndFlushTasks.size()), new LedgerStorageFlushTask(ledgerStorage)); - } - - // invoke all those write/flush tasks all at once concurrently - executor.invokeAll(writeAndFlushTasks).forEach((future) -> { - try { - future.get(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - LOG.error("Write/Flush task failed because of InterruptedException", ie); - Assert.fail("Write/Flush task interrupted"); - } catch (Exception ex) { - LOG.error("Write/Flush task failed because of exception", ex); - Assert.fail("Write/Flush task failed " + ex.getMessage()); - } - }); - - List> readAndFlushTasks = new ArrayList>(); - for (int j = 0; j < numEntries; j++) { - for (int i = 0; i < numOfLedgers; i++) { - readAndFlushTasks.add(new LedgerStorageReadTask(i, j, ledgerStorage)); - } - } - - /* - * add some flush tasks to the list of readtasks list. - */ - for (int i = 0; i < (numOfLedgers * numEntries) / 500; i++) { - readAndFlushTasks.add(rand.nextInt(readAndFlushTasks.size()), new LedgerStorageFlushTask(ledgerStorage)); - } - - // invoke all those read/flush tasks all at once concurrently - executor.invokeAll(readAndFlushTasks).forEach((future) -> { - try { - future.get(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - LOG.error("Read/Flush task failed because of InterruptedException", ie); - Assert.fail("Read/Flush task interrupted"); - } catch (Exception ex) { - LOG.error("Read/Flush task failed because of exception", ex); - Assert.fail("Read/Flush task failed " + ex.getMessage()); - } - }); - - executor.shutdownNow(); - } - - /** - * Test to verify the leastUnflushedLogId logic in EntryLogsStatus. - */ - @Test - public void testEntryLoggersRecentEntryLogsStatus() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - DefaultEntryLogger.RecentEntryLogsStatus recentlyCreatedLogsStatus = entryLogger.recentlyCreatedEntryLogsStatus; - - recentlyCreatedLogsStatus.createdEntryLog(0L); - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 0L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.flushRotatedEntryLog(0L); - // since we marked entrylog - 0 as rotated, LeastUnflushedLogId would be previous rotatedlog+1 - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 1L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.createdEntryLog(1L); - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 1L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.createdEntryLog(2L); - recentlyCreatedLogsStatus.createdEntryLog(3L); - recentlyCreatedLogsStatus.createdEntryLog(4L); - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 1L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.flushRotatedEntryLog(1L); - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 2L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.flushRotatedEntryLog(3L); - // here though we rotated entrylog-3, entrylog-2 is not yet rotated so - // LeastUnflushedLogId should be still 2 - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 2L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.flushRotatedEntryLog(2L); - // entrylog-3 is already rotated, so leastUnflushedLogId should be 4 - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 4L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.flushRotatedEntryLog(4L); - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 5L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.createdEntryLog(5L); - recentlyCreatedLogsStatus.createdEntryLog(7L); - recentlyCreatedLogsStatus.createdEntryLog(9L); - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 5L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.flushRotatedEntryLog(5L); - // since we marked entrylog-5 as rotated, LeastUnflushedLogId would be previous rotatedlog+1 - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 6L, entryLogger.getLeastUnflushedLogId()); - recentlyCreatedLogsStatus.flushRotatedEntryLog(7L); - Assert.assertEquals("entryLogger's leastUnflushedLogId ", 8L, entryLogger.getLeastUnflushedLogId()); - } - - String[] createAndGetLedgerDirs(int numOfLedgerDirs) throws IOException { - File ledgerDir; - File curDir; - String[] ledgerDirsPath = new String[numOfLedgerDirs]; - for (int i = 0; i < numOfLedgerDirs; i++) { - ledgerDir = createTempDir("bkTest", ".dir"); - curDir = BookieImpl.getCurrentDirectory(ledgerDir); - BookieImpl.checkDirectoryStructure(curDir); - ledgerDirsPath[i] = ledgerDir.getAbsolutePath(); - } - return ledgerDirsPath; - } - - /* - * test for validating if the EntryLog/BufferedChannel flushes/forcewrite if the bytes written to it are more than - * flushIntervalInBytes - */ - @Test - public void testFlushIntervalInBytes() throws Exception { - long flushIntervalInBytes = 5000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogPerLedgerEnabled(true); - conf.setFlushIntervalInBytes(flushIntervalInBytes); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerBase entryLogManagerBase = ((EntryLogManagerBase) entryLogger.getEntryLogManager()); - - /* - * when entryLogger is created Header of length EntryLogger.LOGFILE_HEADER_SIZE is created - */ - long ledgerId = 0L; - int firstEntrySize = 1000; - long entry0Position = entryLogger.addEntry(0L, generateEntry(ledgerId, 0L, firstEntrySize)); - // entrylogger writes length of the entry (4 bytes) before writing entry - long expectedUnpersistedBytes = DefaultEntryLogger.LOGFILE_HEADER_SIZE + firstEntrySize + 4; - Assert.assertEquals("Unpersisted Bytes of entrylog", expectedUnpersistedBytes, - entryLogManagerBase.getCurrentLogForLedger(ledgerId).getUnpersistedBytes()); - - /* - * 'flushIntervalInBytes' number of bytes are flushed so BufferedChannel should be forcewritten - */ - int secondEntrySize = (int) (flushIntervalInBytes - expectedUnpersistedBytes); - long entry1Position = entryLogger.addEntry(0L, generateEntry(ledgerId, 1L, secondEntrySize)); - Assert.assertEquals("Unpersisted Bytes of entrylog", 0, - entryLogManagerBase.getCurrentLogForLedger(ledgerId).getUnpersistedBytes()); - - /* - * since entrylog/Bufferedchannel is persisted (forcewritten), we should be able to read the entrylog using - * newEntryLogger - */ - conf.setEntryLogPerLedgerEnabled(false); - DefaultEntryLogger newEntryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManager newEntryLogManager = newEntryLogger.getEntryLogManager(); - Assert.assertEquals("EntryLogManager class type", EntryLogManagerForSingleEntryLog.class, - newEntryLogManager.getClass()); - - ByteBuf buf = newEntryLogger.readEntry(ledgerId, 0L, entry0Position); - long readLedgerId = buf.readLong(); - long readEntryId = buf.readLong(); - Assert.assertEquals("LedgerId", ledgerId, readLedgerId); - Assert.assertEquals("EntryId", 0L, readEntryId); - - buf = newEntryLogger.readEntry(ledgerId, 1L, entry1Position); - readLedgerId = buf.readLong(); - readEntryId = buf.readLong(); - Assert.assertEquals("LedgerId", ledgerId, readLedgerId); - Assert.assertEquals("EntryId", 1L, readEntryId); - } - - @Test - public void testReadEntryWithoutLedgerID() throws Exception { - List locations = new ArrayList<>(); - // `+ 1` is not a typo: create one more log file than the max number of o cached readers - for (int i = 0; i < 10; i++) { - ByteBuf e = makeEntry(1L, i, 100); - long loc = entryLogger.addEntry(1L, e.slice()); - locations.add(loc); - } - entryLogger.flush(); - for (Long loc : locations) { - int i = locations.indexOf(loc); - ByteBuf data = entryLogger.readEntry(loc); - assertEntryEquals(data, makeEntry(1L, i, 100)); - long readLedgerId = data.readLong(); - long readEntryId = data.readLong(); - Assert.assertEquals("LedgerId", 1L, readLedgerId); - Assert.assertEquals("EntryId", i, readEntryId); - ReferenceCountUtil.release(data); - } - } - - - /* - * tests basic logic of EntryLogManager interface for - * EntryLogManagerForEntryLogPerLedger. - */ - @Test - public void testEntryLogManagerInterfaceForEntryLogPerLedger() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) entryLogger - .getEntryLogManager(); - - Assert.assertEquals("Number of current active EntryLogs ", 0, entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of Rotated Logs ", 0, entryLogManager.getRotatedLogChannels().size()); - - int numOfLedgers = 5; - int numOfThreadsPerLedger = 10; - validateLockAcquireAndRelease(numOfLedgers, numOfThreadsPerLedger, entryLogManager); - - for (long i = 0; i < numOfLedgers; i++) { - entryLogManager.setCurrentLogForLedgerAndAddToRotate(i, - createDummyBufferedLogChannel(entryLogger, i, conf)); - } - - for (long i = 0; i < numOfLedgers; i++) { - Assert.assertEquals("LogChannel for ledger: " + i, entryLogManager.getCurrentLogIfPresent(i), - entryLogManager.getCurrentLogForLedger(i)); - } - - Assert.assertEquals("Number of current active EntryLogs ", numOfLedgers, - entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of Rotated Logs ", 0, entryLogManager.getRotatedLogChannels().size()); - - for (long i = 0; i < numOfLedgers; i++) { - entryLogManager.setCurrentLogForLedgerAndAddToRotate(i, - createDummyBufferedLogChannel(entryLogger, numOfLedgers + i, conf)); - } - - /* - * since new entryLogs are set for all the ledgers, previous entrylogs would be added to rotatedLogChannels - */ - Assert.assertEquals("Number of current active EntryLogs ", numOfLedgers, - entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of Rotated Logs ", numOfLedgers, - entryLogManager.getRotatedLogChannels().size()); - - for (long i = 0; i < numOfLedgers; i++) { - entryLogManager.setCurrentLogForLedgerAndAddToRotate(i, - createDummyBufferedLogChannel(entryLogger, 2 * numOfLedgers + i, conf)); - } - - /* - * again since new entryLogs are set for all the ledgers, previous entrylogs would be added to - * rotatedLogChannels - */ - Assert.assertEquals("Number of current active EntryLogs ", numOfLedgers, - entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of Rotated Logs ", 2 * numOfLedgers, - entryLogManager.getRotatedLogChannels().size()); - - for (BufferedLogChannel logChannel : entryLogManager.getRotatedLogChannels()) { - entryLogManager.getRotatedLogChannels().remove(logChannel); - } - Assert.assertEquals("Number of Rotated Logs ", 0, entryLogManager.getRotatedLogChannels().size()); - - // entrylogid is sequential - for (long i = 0; i < numOfLedgers; i++) { - assertEquals("EntryLogid for Ledger " + i, 2 * numOfLedgers + i, - entryLogManager.getCurrentLogForLedger(i).getLogId()); - } - - for (long i = 2 * numOfLedgers; i < (3 * numOfLedgers); i++) { - assertTrue("EntryLog with logId: " + i + " should be present", - entryLogManager.getCurrentLogIfPresent(i) != null); - } - } - - private DefaultEntryLogger.BufferedLogChannel createDummyBufferedLogChannel(DefaultEntryLogger entryLogger, - long logid, - ServerConfiguration servConf) - throws IOException { - File tmpFile = File.createTempFile("entrylog", logid + ""); - tmpFile.deleteOnExit(); - FileChannel fc = new RandomAccessFile(tmpFile, "rw").getChannel(); - DefaultEntryLogger.BufferedLogChannel logChannel = - new BufferedLogChannel(UnpooledByteBufAllocator.DEFAULT, fc, 10, 10, - logid, tmpFile, servConf.getFlushIntervalInBytes()); - return logChannel; - } - - /* - * validates the concurrency aspect of entryLogManager's lock - * - * Executor of fixedThreadPool of size 'numOfLedgers * numOfThreadsPerLedger' is created and the same number - * of tasks are submitted to the Executor. In each task, lock of that ledger is acquired and then released. - */ - private void validateLockAcquireAndRelease(int numOfLedgers, int numOfThreadsPerLedger, - EntryLogManagerForEntryLogPerLedger entryLogManager) throws InterruptedException { - ExecutorService tpe = Executors.newFixedThreadPool(numOfLedgers * numOfThreadsPerLedger); - CountDownLatch latchToStart = new CountDownLatch(1); - CountDownLatch latchToWait = new CountDownLatch(1); - AtomicInteger numberOfThreadsAcquiredLock = new AtomicInteger(0); - AtomicBoolean irptExceptionHappened = new AtomicBoolean(false); - Random rand = new Random(); - - for (int i = 0; i < numOfLedgers * numOfThreadsPerLedger; i++) { - long ledgerId = i % numOfLedgers; - tpe.submit(() -> { - try { - latchToStart.await(); - Lock lock = entryLogManager.getLock(ledgerId); - lock.lock(); - numberOfThreadsAcquiredLock.incrementAndGet(); - latchToWait.await(); - lock.unlock(); - } catch (InterruptedException | IOException e) { - irptExceptionHappened.set(true); - } - }); - } - - assertEquals("Number Of Threads acquired Lock", 0, numberOfThreadsAcquiredLock.get()); - latchToStart.countDown(); - Thread.sleep(1000); - /* - * since there are only "numOfLedgers" ledgers, only < "numOfLedgers" - * threads should have been able to acquire lock, because multiple - * ledgers can end up getting same lock because their hashcode might - * fall in the same bucket. - * - * - * After acquiring the lock there must be waiting on 'latchToWait' latch - */ - int currentNumberOfThreadsAcquiredLock = numberOfThreadsAcquiredLock.get(); - assertTrue("Number Of Threads acquired Lock " + currentNumberOfThreadsAcquiredLock, - (currentNumberOfThreadsAcquiredLock > 0) && (currentNumberOfThreadsAcquiredLock <= numOfLedgers)); - latchToWait.countDown(); - Thread.sleep(2000); - assertEquals("Number Of Threads acquired Lock", numOfLedgers * numOfThreadsPerLedger, - numberOfThreadsAcquiredLock.get()); - } - - /* - * test EntryLogManager.EntryLogManagerForEntryLogPerLedger removes the - * ledger from its cache map if entry is not added to that ledger or its - * corresponding state is not accessed for more than evictionPeriod - * - * @throws Exception - */ - @Test - public void testEntryLogManagerExpiryRemoval() throws Exception { - int evictionPeriod = 1; - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - conf.setEntrylogMapAccessExpiryTimeInSeconds(evictionPeriod); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = - (EntryLogManagerForEntryLogPerLedger) entryLogger.getEntryLogManager(); - - long ledgerId = 0L; - - BufferedLogChannel logChannel = createDummyBufferedLogChannel(entryLogger, 0, conf); - entryLogManager.setCurrentLogForLedgerAndAddToRotate(ledgerId, logChannel); - - BufferedLogChannel currentLogForLedger = entryLogManager.getCurrentLogForLedger(ledgerId); - assertEquals("LogChannel for ledger " + ledgerId + " should match", logChannel, currentLogForLedger); - - Thread.sleep(evictionPeriod * 1000 + 100); - entryLogManager.doEntryLogMapCleanup(); - - /* - * since for more than evictionPeriod, that ledger is not accessed and cache is cleaned up, mapping for that - * ledger should not be available anymore - */ - currentLogForLedger = entryLogManager.getCurrentLogForLedger(ledgerId); - assertEquals("LogChannel for ledger " + ledgerId + " should be null", null, currentLogForLedger); - Assert.assertEquals("Number of current active EntryLogs ", 0, entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of rotated EntryLogs ", 1, entryLogManager.getRotatedLogChannels().size()); - Assert.assertTrue("CopyOfRotatedLogChannels should contain the created LogChannel", - entryLogManager.getRotatedLogChannels().contains(logChannel)); - - Assert.assertTrue("since mapentry must have been evicted, it should be null", - (entryLogManager.getCacheAsMap().get(ledgerId) == null) - || (entryLogManager.getCacheAsMap().get(ledgerId).getEntryLogWithDirInfo() == null)); - } - - /* - * tests if the maximum size of cache (maximumNumberOfActiveEntryLogs) is - * honored in EntryLogManagerForEntryLogPerLedger's cache eviction policy. - */ - @Test - public void testCacheMaximumSizeEvictionPolicy() throws Exception { - entryLogger.close(); - final int cacheMaximumSize = 20; - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(1)); - conf.setMaximumNumberOfActiveEntryLogs(cacheMaximumSize); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = - (EntryLogManagerForEntryLogPerLedger) entryLogger.getEntryLogManager(); - - for (int i = 0; i < cacheMaximumSize + 10; i++) { - entryLogManager.createNewLog(i); - int cacheSize = entryLogManager.getCacheAsMap().size(); - Assert.assertTrue("Cache maximum size is expected to be less than " + cacheMaximumSize - + " but current cacheSize is " + cacheSize, cacheSize <= cacheMaximumSize); - } - } - - @Test - public void testLongLedgerIdsWithEntryLogPerLedger() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(1)); - conf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) entryLogger - .getEntryLogManager(); - - int numOfLedgers = 5; - int numOfEntries = 4; - long[][] pos = new long[numOfLedgers][numOfEntries]; - for (int i = 0; i < numOfLedgers; i++) { - long ledgerId = Long.MAX_VALUE - i; - entryLogManager.createNewLog(ledgerId); - for (int entryId = 0; entryId < numOfEntries; entryId++) { - pos[i][entryId] = entryLogger.addEntry(ledgerId, generateEntry(ledgerId, entryId).nioBuffer()); - } - } - /* - * do checkpoint to make sure entrylog files are persisted - */ - entryLogger.checkpoint(); - - for (int i = 0; i < numOfLedgers; i++) { - long ledgerId = Long.MAX_VALUE - i; - for (int entryId = 0; entryId < numOfEntries; entryId++) { - String expectedValue = generateDataString(ledgerId, entryId); - ByteBuf buf = entryLogger.readEntry(ledgerId, entryId, pos[i][entryId]); - long readLedgerId = buf.readLong(); - long readEntryId = buf.readLong(); - byte[] readData = new byte[buf.readableBytes()]; - buf.readBytes(readData); - assertEquals("LedgerId ", ledgerId, readLedgerId); - assertEquals("EntryId ", entryId, readEntryId); - assertEquals("Entry Data ", expectedValue, new String(readData)); - } - } - } - - /* - * when entrylog for ledger is removed from ledgerIdEntryLogMap, then - * ledgermap should be appended to that entrylog, before moving that - * entrylog to rotatedlogchannels. - */ - @Test - public void testAppendLedgersMapOnCacheRemoval() throws Exception { - final int cacheMaximumSize = 5; - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogFilePreAllocationEnabled(true); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(1)); - conf.setMaximumNumberOfActiveEntryLogs(cacheMaximumSize); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) entryLogger - .getEntryLogManager(); - - long ledgerId = 0L; - entryLogManager.createNewLog(ledgerId); - int entrySize = 200; - int numOfEntries = 4; - for (int i = 0; i < numOfEntries; i++) { - entryLogger.addEntry(ledgerId, generateEntry(ledgerId, i, entrySize)); - } - - BufferedLogChannel logChannelForledger = entryLogManager.getCurrentLogForLedger(ledgerId); - long logIdOfLedger = logChannelForledger.getLogId(); - /* - * do checkpoint to make sure entrylog files are persisted - */ - entryLogger.checkpoint(); - - try { - entryLogger.extractEntryLogMetadataFromIndex(logIdOfLedger); - } catch (IOException ie) { - // expected because appendLedgersMap wouldn't have been called - } - - /* - * create entrylogs for more ledgers, so that ledgerIdEntryLogMap would - * reach its limit and remove the oldest entrylog. - */ - for (int i = 1; i <= cacheMaximumSize; i++) { - entryLogManager.createNewLog(i); - } - /* - * do checkpoint to make sure entrylog files are persisted - */ - entryLogger.checkpoint(); - - EntryLogMetadata entryLogMetadata = entryLogger.extractEntryLogMetadataFromIndex(logIdOfLedger); - ConcurrentLongLongHashMap ledgersMap = entryLogMetadata.getLedgersMap(); - Assert.assertEquals("There should be only one entry in entryLogMetadata", 1, ledgersMap.size()); - Assert.assertTrue("Usage should be 1", Double.compare(1.0, entryLogMetadata.getUsage()) == 0); - Assert.assertEquals("Total size of entries", (entrySize + 4) * numOfEntries, ledgersMap.get(ledgerId)); - } - - /** - * test EntryLogManager.EntryLogManagerForEntryLogPerLedger doesn't removes - * the ledger from its cache map if ledger's corresponding state is accessed - * within the evictionPeriod. - * - * @throws Exception - */ - @Test - public void testExpiryRemovalByAccessingOnAnotherThread() throws Exception { - int evictionPeriod = 1; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - conf.setEntrylogMapAccessExpiryTimeInSeconds(evictionPeriod); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = - (EntryLogManagerForEntryLogPerLedger) entryLogger.getEntryLogManager(); - - long ledgerId = 0L; - - BufferedLogChannel newLogChannel = createDummyBufferedLogChannel(entryLogger, 1, conf); - entryLogManager.setCurrentLogForLedgerAndAddToRotate(ledgerId, newLogChannel); - - Thread t = new Thread() { - public void run() { - try { - Thread.sleep((evictionPeriod * 1000) / 2); - entryLogManager.getCurrentLogForLedger(ledgerId); - } catch (InterruptedException | IOException e) { - } - } - }; - - t.start(); - Thread.sleep(evictionPeriod * 1000 + 100); - entryLogManager.doEntryLogMapCleanup(); - - /* - * in this scenario, that ledger is accessed by other thread during - * eviction period time, so it should not be evicted. - */ - BufferedLogChannel currentLogForLedger = entryLogManager.getCurrentLogForLedger(ledgerId); - assertEquals("LogChannel for ledger " + ledgerId, newLogChannel, currentLogForLedger); - Assert.assertEquals("Number of current active EntryLogs ", 1, entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of rotated EntryLogs ", 0, entryLogManager.getRotatedLogChannels().size()); - } - - /** - * test EntryLogManager.EntryLogManagerForEntryLogPerLedger removes the - * ledger from its cache map if entry is not added to that ledger or its - * corresponding state is not accessed for more than evictionPeriod. In this - * testcase we try to call unrelated methods or access state of other - * ledgers within the eviction period. - * - * @throws Exception - */ - @Test - public void testExpiryRemovalByAccessingNonCacheRelatedMethods() throws Exception { - int evictionPeriod = 1; - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - conf.setEntrylogMapAccessExpiryTimeInSeconds(evictionPeriod); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = - (EntryLogManagerForEntryLogPerLedger) entryLogger.getEntryLogManager(); - - long ledgerId = 0L; - - BufferedLogChannel newLogChannel = createDummyBufferedLogChannel(entryLogger, 1, conf); - entryLogManager.setCurrentLogForLedgerAndAddToRotate(ledgerId, newLogChannel); - - AtomicBoolean exceptionOccured = new AtomicBoolean(false); - Thread t = new Thread() { - public void run() { - try { - Thread.sleep(500); - /* - * any of the following operations should not access entry - * of 'ledgerId' in the cache - */ - entryLogManager.getCopyOfCurrentLogs(); - entryLogManager.getRotatedLogChannels(); - entryLogManager.getCurrentLogIfPresent(newLogChannel.getLogId()); - entryLogManager.getDirForNextEntryLog(ledgerDirsManager.getWritableLedgerDirs()); - long newLedgerId = 100; - BufferedLogChannel logChannelForNewLedger = - createDummyBufferedLogChannel(entryLogger, newLedgerId, conf); - entryLogManager.setCurrentLogForLedgerAndAddToRotate(newLedgerId, logChannelForNewLedger); - entryLogManager.getCurrentLogIfPresent(newLedgerId); - } catch (Exception e) { - LOG.error("Got Exception in thread", e); - exceptionOccured.set(true); - } - } - }; - - t.start(); - Thread.sleep(evictionPeriod * 1000 + 100); - entryLogManager.doEntryLogMapCleanup(); - Assert.assertFalse("Exception occured in thread, which is not expected", exceptionOccured.get()); - - /* - * since for more than evictionPeriod, that ledger is not accessed and cache is cleaned up, mapping for that - * ledger should not be available anymore - */ - BufferedLogChannel currentLogForLedger = entryLogManager.getCurrentLogForLedger(ledgerId); - assertEquals("LogChannel for ledger " + ledgerId + " should be null", null, currentLogForLedger); - // expected number of current active entryLogs is 1 since we created entrylog for 'newLedgerId' - Assert.assertEquals("Number of current active EntryLogs ", 1, entryLogManager.getCopyOfCurrentLogs().size()); - Assert.assertEquals("Number of rotated EntryLogs ", 1, entryLogManager.getRotatedLogChannels().size()); - Assert.assertTrue("CopyOfRotatedLogChannels should contain the created LogChannel", - entryLogManager.getRotatedLogChannels().contains(newLogChannel)); - - Assert.assertTrue("since mapentry must have been evicted, it should be null", - (entryLogManager.getCacheAsMap().get(ledgerId) == null) - || (entryLogManager.getCacheAsMap().get(ledgerId).getEntryLogWithDirInfo() == null)); - } - - /* - * testing EntryLogger functionality (addEntry/createNewLog/flush) and EntryLogManager with entryLogPerLedger - * enabled - */ - @Test - public void testEntryLogManagerForEntryLogPerLedger() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogPerLedgerEnabled(true); - conf.setFlushIntervalInBytes(10000000); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerBase entryLogManager = (EntryLogManagerBase) entryLogger.getEntryLogManager(); - Assert.assertEquals("EntryLogManager class type", EntryLogManagerForEntryLogPerLedger.class, - entryLogManager.getClass()); - - int numOfActiveLedgers = 20; - int numEntries = 5; - - for (int j = 0; j < numEntries; j++) { - for (long i = 0; i < numOfActiveLedgers; i++) { - entryLogger.addEntry(i, generateEntry(i, j)); - } - } - - for (long i = 0; i < numOfActiveLedgers; i++) { - BufferedLogChannel logChannel = entryLogManager.getCurrentLogForLedger(i); - Assert.assertTrue("unpersistedBytes should be greater than LOGFILE_HEADER_SIZE", - logChannel.getUnpersistedBytes() > DefaultEntryLogger.LOGFILE_HEADER_SIZE); - } - - for (long i = 0; i < numOfActiveLedgers; i++) { - entryLogManager.createNewLog(i); - } - - /* - * since we created new entrylog for all the activeLedgers, entrylogs of all the ledgers - * should be rotated and hence the size of copyOfRotatedLogChannels should be numOfActiveLedgers - */ - List rotatedLogs = entryLogManager.getRotatedLogChannels(); - Assert.assertEquals("Number of rotated entrylogs", numOfActiveLedgers, rotatedLogs.size()); - - /* - * Since newlog is created for all slots, so they are moved to rotated logs and hence unpersistedBytes of all - * the slots should be just EntryLogger.LOGFILE_HEADER_SIZE - * - */ - for (long i = 0; i < numOfActiveLedgers; i++) { - BufferedLogChannel logChannel = entryLogManager.getCurrentLogForLedger(i); - Assert.assertEquals("unpersistedBytes should be LOGFILE_HEADER_SIZE", - DefaultEntryLogger.LOGFILE_HEADER_SIZE, logChannel.getUnpersistedBytes()); - } - - for (int j = numEntries; j < 2 * numEntries; j++) { - for (long i = 0; i < numOfActiveLedgers; i++) { - entryLogger.addEntry(i, generateEntry(i, j)); - } - } - - for (long i = 0; i < numOfActiveLedgers; i++) { - BufferedLogChannel logChannel = entryLogManager.getCurrentLogForLedger(i); - Assert.assertTrue("unpersistedBytes should be greater than LOGFILE_HEADER_SIZE", - logChannel.getUnpersistedBytes() > DefaultEntryLogger.LOGFILE_HEADER_SIZE); - } - - Assert.assertEquals("LeastUnflushedloggerID", 0, entryLogger.getLeastUnflushedLogId()); - - /* - * here flush is called so all the rotatedLogChannels should be file closed and there shouldn't be any - * rotatedlogchannel and also leastUnflushedLogId should be advanced to numOfActiveLedgers - */ - entryLogger.flush(); - Assert.assertEquals("Number of rotated entrylogs", 0, entryLogManager.getRotatedLogChannels().size()); - Assert.assertEquals("LeastUnflushedloggerID", numOfActiveLedgers, entryLogger.getLeastUnflushedLogId()); - - /* - * after flush (flushCurrentLogs) unpersistedBytes should be 0. - */ - for (long i = 0; i < numOfActiveLedgers; i++) { - BufferedLogChannel logChannel = entryLogManager.getCurrentLogForLedger(i); - Assert.assertEquals("unpersistedBytes should be 0", 0L, logChannel.getUnpersistedBytes()); - } - } - - @Test - public void testSingleEntryLogCreateNewLog() throws Exception { - Assert.assertTrue(entryLogger.getEntryLogManager() instanceof EntryLogManagerForSingleEntryLog); - EntryLogManagerForSingleEntryLog singleEntryLog = - (EntryLogManagerForSingleEntryLog) entryLogger.getEntryLogManager(); - EntryLogManagerForSingleEntryLog mockSingleEntryLog = spy(singleEntryLog); - BufferedLogChannel activeLogChannel = mockSingleEntryLog.getCurrentLogForLedgerForAddEntry(1, 1024, true); - Assert.assertTrue(activeLogChannel != null); - - verify(mockSingleEntryLog, times(1)).createNewLog(anyLong(), anyString()); - // `readEntryLogHardLimit` and `reachEntryLogLimit` should not call if new create log - verify(mockSingleEntryLog, times(0)).reachEntryLogLimit(any(), anyLong()); - verify(mockSingleEntryLog, times(0)).readEntryLogHardLimit(any(), anyLong()); - } - - /* - * with entryLogPerLedger enabled, create multiple entrylogs, add entries of ledgers and read them before and after - * flush - */ - @Test - public void testReadAddCallsOfMultipleEntryLogs() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - // pre allocation enabled - conf.setEntryLogFilePreAllocationEnabled(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerBase entryLogManagerBase = ((EntryLogManagerBase) entryLogger.getEntryLogManager()); - - int numOfActiveLedgers = 10; - int numEntries = 10; - long[][] positions = new long[numOfActiveLedgers][]; - for (int i = 0; i < numOfActiveLedgers; i++) { - positions[i] = new long[numEntries]; - } - - /* - * addentries to the ledgers - */ - for (int j = 0; j < numEntries; j++) { - for (int i = 0; i < numOfActiveLedgers; i++) { - positions[i][j] = entryLogger.addEntry((long) i, generateEntry(i, j)); - long entryLogId = (positions[i][j] >> 32L); - /** - * - * Though EntryLogFilePreAllocation is enabled, Since things are not done concurrently here, - * entryLogIds will be sequential. - */ - Assert.assertEquals("EntryLogId for ledger: " + i, i, entryLogId); - } - } - - /* - * read the entries which are written - */ - for (int j = 0; j < numEntries; j++) { - for (int i = 0; i < numOfActiveLedgers; i++) { - String expectedValue = "ledger-" + i + "-" + j; - ByteBuf buf = entryLogger.readEntry(i, j, positions[i][j]); - long ledgerId = buf.readLong(); - long entryId = buf.readLong(); - byte[] data = new byte[buf.readableBytes()]; - buf.readBytes(data); - assertEquals("LedgerId ", i, ledgerId); - assertEquals("EntryId ", j, entryId); - assertEquals("Entry Data ", expectedValue, new String(data)); - } - } - - for (long i = 0; i < numOfActiveLedgers; i++) { - entryLogManagerBase.createNewLog(i); - } - - entryLogManagerBase.flushRotatedLogs(); - - // reading after flush of rotatedlogs - for (int j = 0; j < numEntries; j++) { - for (int i = 0; i < numOfActiveLedgers; i++) { - String expectedValue = "ledger-" + i + "-" + j; - ByteBuf buf = entryLogger.readEntry(i, j, positions[i][j]); - long ledgerId = buf.readLong(); - long entryId = buf.readLong(); - byte[] data = new byte[buf.readableBytes()]; - buf.readBytes(data); - assertEquals("LedgerId ", i, ledgerId); - assertEquals("EntryId ", j, entryId); - assertEquals("Entry Data ", expectedValue, new String(data)); - } - } - } - - class ReadTask implements Callable { - long ledgerId; - int entryId; - long position; - DefaultEntryLogger entryLogger; - - ReadTask(long ledgerId, int entryId, long position, DefaultEntryLogger entryLogger) { - this.ledgerId = ledgerId; - this.entryId = entryId; - this.position = position; - this.entryLogger = entryLogger; - } - - @Override - public Boolean call() throws IOException { - try { - ByteBuf expectedByteBuf = generateEntry(ledgerId, entryId); - ByteBuf actualByteBuf = entryLogger.readEntry(ledgerId, entryId, position); - if (!expectedByteBuf.equals(actualByteBuf)) { - LOG.error("Expected Entry: {} Actual Entry: {}", expectedByteBuf.toString(Charset.defaultCharset()), - actualByteBuf.toString(Charset.defaultCharset())); - throw new IOException("Expected Entry: " + expectedByteBuf.toString(Charset.defaultCharset()) - + " Actual Entry: " + actualByteBuf.toString(Charset.defaultCharset())); - } - } catch (IOException e) { - LOG.error("Got Exception for GetEntry call. LedgerId: " + ledgerId + " entryId: " + entryId, e); - throw new IOException("Got Exception for GetEntry call. LedgerId: " + ledgerId + " entryId: " + entryId, - e); - } - return true; - } - } - - /* - * test concurrent read operations of entries from flushed rotatedlogs with entryLogPerLedgerEnabled - */ - @Test - public void testConcurrentReadCallsAfterEntryLogsAreRotated() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogPerLedgerEnabled(true); - conf.setFlushIntervalInBytes(1000 * 25); - conf.setLedgerDirNames(createAndGetLedgerDirs(3)); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - int numOfActiveLedgers = 15; - int numEntries = 2000; - final AtomicLongArray positions = new AtomicLongArray(numOfActiveLedgers * numEntries); - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) - entryLogger.getEntryLogManager(); - - for (int i = 0; i < numOfActiveLedgers; i++) { - for (int j = 0; j < numEntries; j++) { - positions.set(i * numEntries + j, entryLogger.addEntry((long) i, generateEntry(i, j))); - long entryLogId = (positions.get(i * numEntries + j) >> 32L); - /** - * - * Though EntryLogFilePreAllocation is enabled, Since things are not done concurrently here, entryLogIds - * will be sequential. - */ - Assert.assertEquals("EntryLogId for ledger: " + i, i, entryLogId); - } - } - - for (long i = 0; i < numOfActiveLedgers; i++) { - entryLogManager.createNewLog(i); - } - entryLogManager.flushRotatedLogs(); - - // reading after flush of rotatedlogs - ArrayList readTasks = new ArrayList(); - for (int i = 0; i < numOfActiveLedgers; i++) { - for (int j = 0; j < numEntries; j++) { - readTasks.add(new ReadTask(i, j, positions.get(i * numEntries + j), entryLogger)); - } - } - - ExecutorService executor = Executors.newFixedThreadPool(40); - executor.invokeAll(readTasks).forEach((future) -> { - try { - future.get(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - LOG.error("Read/Flush task failed because of InterruptedException", ie); - Assert.fail("Read/Flush task interrupted"); - } catch (Exception ex) { - LOG.error("Read/Flush task failed because of exception", ex); - Assert.fail("Read/Flush task failed " + ex.getMessage()); - } - }); - } - - /** - * testcase to validate when ledgerdirs become full and eventually all - * ledgerdirs become full. Later a ledgerdir becomes writable. - */ - @Test - public void testEntryLoggerAddEntryWhenLedgerDirsAreFull() throws Exception { - int numberOfLedgerDirs = 3; - List ledgerDirs = new ArrayList(); - String[] ledgerDirsPath = new String[numberOfLedgerDirs]; - List curDirs = new ArrayList(); - - File ledgerDir; - File curDir; - for (int i = 0; i < numberOfLedgerDirs; i++) { - ledgerDir = createTempDir("bkTest", ".dir").getAbsoluteFile(); - curDir = BookieImpl.getCurrentDirectory(ledgerDir); - BookieImpl.checkDirectoryStructure(curDir); - ledgerDirs.add(ledgerDir); - ledgerDirsPath[i] = ledgerDir.getPath(); - curDirs.add(curDir); - } - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - // pre-allocation is disabled - conf.setEntryLogFilePreAllocationEnabled(false); - conf.setEntryLogPerLedgerEnabled(true); - conf.setLedgerDirNames(ledgerDirsPath); - - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) - entryLogger.getEntryLogManager(); - Assert.assertEquals("EntryLogManager class type", EntryLogManagerForEntryLogPerLedger.class, - entryLogManager.getClass()); - - entryLogger.addEntry(0L, generateEntry(0, 1)); - entryLogger.addEntry(1L, generateEntry(1, 1)); - entryLogger.addEntry(2L, generateEntry(2, 1)); - - File ledgerDirForLedger0 = entryLogManager.getCurrentLogForLedger(0L).getLogFile().getParentFile(); - File ledgerDirForLedger1 = entryLogManager.getCurrentLogForLedger(1L).getLogFile().getParentFile(); - File ledgerDirForLedger2 = entryLogManager.getCurrentLogForLedger(2L).getLogFile().getParentFile(); - - Set ledgerDirsSet = new HashSet(); - ledgerDirsSet.add(ledgerDirForLedger0); - ledgerDirsSet.add(ledgerDirForLedger1); - ledgerDirsSet.add(ledgerDirForLedger2); - - /* - * since there are 3 ledgerdirs, entrylogs for all the 3 ledgers should be in different ledgerdirs. - */ - Assert.assertEquals("Current active LedgerDirs size", 3, ledgerDirs.size()); - Assert.assertEquals("Number of rotated logchannels", 0, entryLogManager.getRotatedLogChannels().size()); - - /* - * ledgerDirForLedger0 is added to filledDirs, for ledger0 new entrylog should not be created in - * ledgerDirForLedger0 - */ - ledgerDirsManager.addToFilledDirs(ledgerDirForLedger0); - addEntryAndValidateFolders(entryLogger, entryLogManager, 2, ledgerDirForLedger0, false, ledgerDirForLedger1, - ledgerDirForLedger2); - Assert.assertEquals("Number of rotated logchannels", 1, entryLogManager.getRotatedLogChannels().size()); - - /* - * ledgerDirForLedger1 is also added to filledDirs, so for all the ledgers new entryLogs should be in - * ledgerDirForLedger2 - */ - ledgerDirsManager.addToFilledDirs(ledgerDirForLedger1); - addEntryAndValidateFolders(entryLogger, entryLogManager, 3, ledgerDirForLedger2, true, ledgerDirForLedger2, - ledgerDirForLedger2); - Assert.assertTrue("Number of rotated logchannels", (2 <= entryLogManager.getRotatedLogChannels().size()) - && (entryLogManager.getRotatedLogChannels().size() <= 3)); - int numOfRotatedLogChannels = entryLogManager.getRotatedLogChannels().size(); - - /* - * since ledgerDirForLedger2 is added to filleddirs, all the dirs are full. If all the dirs are full then it - * will continue to use current entrylogs for new entries instead of creating new one. So for all the ledgers - * ledgerdirs should be same as before - ledgerDirForLedger2 - */ - ledgerDirsManager.addToFilledDirs(ledgerDirForLedger2); - addEntryAndValidateFolders(entryLogger, entryLogManager, 4, ledgerDirForLedger2, true, ledgerDirForLedger2, - ledgerDirForLedger2); - Assert.assertEquals("Number of rotated logchannels", numOfRotatedLogChannels, - entryLogManager.getRotatedLogChannels().size()); - - /* - * ledgerDirForLedger1 is added back to writableDirs, so new entrylog for all the ledgers should be created in - * ledgerDirForLedger1 - */ - ledgerDirsManager.addToWritableDirs(ledgerDirForLedger1, true); - addEntryAndValidateFolders(entryLogger, entryLogManager, 4, ledgerDirForLedger1, true, ledgerDirForLedger1, - ledgerDirForLedger1); - Assert.assertEquals("Number of rotated logchannels", numOfRotatedLogChannels + 3, - entryLogManager.getRotatedLogChannels().size()); - } - - /* - * in this method we add an entry and validate the ledgerdir of the - * currentLogForLedger against the provided expected ledgerDirs. - */ - void addEntryAndValidateFolders(DefaultEntryLogger entryLogger, EntryLogManagerBase entryLogManager, int entryId, - File expectedDirForLedger0, boolean equalsForLedger0, File expectedDirForLedger1, - File expectedDirForLedger2) throws IOException { - entryLogger.addEntry(0L, generateEntry(0, entryId)); - entryLogger.addEntry(1L, generateEntry(1, entryId)); - entryLogger.addEntry(2L, generateEntry(2, entryId)); - - if (equalsForLedger0) { - Assert.assertEquals("LedgerDir for ledger 0 after adding entry " + entryId, expectedDirForLedger0, - entryLogManager.getCurrentLogForLedger(0L).getLogFile().getParentFile()); - } else { - Assert.assertNotEquals("LedgerDir for ledger 0 after adding entry " + entryId, expectedDirForLedger0, - entryLogManager.getCurrentLogForLedger(0L).getLogFile().getParentFile()); - } - Assert.assertEquals("LedgerDir for ledger 1 after adding entry " + entryId, expectedDirForLedger1, - entryLogManager.getCurrentLogForLedger(1L).getLogFile().getParentFile()); - Assert.assertEquals("LedgerDir for ledger 2 after adding entry " + entryId, expectedDirForLedger2, - entryLogManager.getCurrentLogForLedger(2L).getLogFile().getParentFile()); - } - - /* - * entries added using entrylogger with entryLogPerLedger enabled and the same entries are read using entrylogger - * with entryLogPerLedger disabled - */ - @Test - public void testSwappingEntryLogManagerFromEntryLogPerLedgerToSingle() throws Exception { - testSwappingEntryLogManager(true, false); - } - - /* - * entries added using entrylogger with entryLogPerLedger disabled and the same entries are read using entrylogger - * with entryLogPerLedger enabled - */ - @Test - public void testSwappingEntryLogManagerFromSingleToEntryLogPerLedger() throws Exception { - testSwappingEntryLogManager(false, true); - } - - public void testSwappingEntryLogManager(boolean initialEntryLogPerLedgerEnabled, - boolean laterEntryLogPerLedgerEnabled) throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setEntryLogPerLedgerEnabled(initialEntryLogPerLedgerEnabled); - conf.setLedgerDirNames(createAndGetLedgerDirs(2)); - // pre allocation enabled - conf.setEntryLogFilePreAllocationEnabled(true); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DefaultEntryLogger defaultEntryLogger = new DefaultEntryLogger(conf, ledgerDirsManager); - EntryLogManagerBase entryLogManager = (EntryLogManagerBase) defaultEntryLogger.getEntryLogManager(); - Assert.assertEquals( - "EntryLogManager class type", initialEntryLogPerLedgerEnabled - ? EntryLogManagerForEntryLogPerLedger.class : EntryLogManagerForSingleEntryLog.class, - entryLogManager.getClass()); - - int numOfActiveLedgers = 10; - int numEntries = 10; - long[][] positions = new long[numOfActiveLedgers][]; - for (int i = 0; i < numOfActiveLedgers; i++) { - positions[i] = new long[numEntries]; - } - - /* - * addentries to the ledgers - */ - for (int j = 0; j < numEntries; j++) { - for (int i = 0; i < numOfActiveLedgers; i++) { - positions[i][j] = defaultEntryLogger.addEntry((long) i, generateEntry(i, j)); - long entryLogId = (positions[i][j] >> 32L); - if (initialEntryLogPerLedgerEnabled) { - Assert.assertEquals("EntryLogId for ledger: " + i, i, entryLogId); - } else { - Assert.assertEquals("EntryLogId for ledger: " + i, 0, entryLogId); - } - } - } - - for (long i = 0; i < numOfActiveLedgers; i++) { - entryLogManager.createNewLog(i); - } - - /** - * since new entrylog is created for all the ledgers, the previous - * entrylogs must be rotated and with the following flushRotatedLogs - * call they should be forcewritten and file should be closed. - */ - entryLogManager.flushRotatedLogs(); - - /* - * new entrylogger and entryLogManager are created with - * 'laterEntryLogPerLedgerEnabled' conf - */ - conf.setEntryLogPerLedgerEnabled(laterEntryLogPerLedgerEnabled); - LedgerDirsManager newLedgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - DefaultEntryLogger newEntryLogger = new DefaultEntryLogger(conf, newLedgerDirsManager); - EntryLogManager newEntryLogManager = newEntryLogger.getEntryLogManager(); - Assert.assertEquals("EntryLogManager class type", - laterEntryLogPerLedgerEnabled ? EntryLogManagerForEntryLogPerLedger.class - : EntryLogManagerForSingleEntryLog.class, - newEntryLogManager.getClass()); - - /* - * read the entries (which are written with previous entrylogger) with - * new entrylogger - */ - for (int j = 0; j < numEntries; j++) { - for (int i = 0; i < numOfActiveLedgers; i++) { - String expectedValue = "ledger-" + i + "-" + j; - ByteBuf buf = newEntryLogger.readEntry(i, j, positions[i][j]); - long ledgerId = buf.readLong(); - long entryId = buf.readLong(); - byte[] data = new byte[buf.readableBytes()]; - buf.readBytes(data); - assertEquals("LedgerId ", i, ledgerId); - assertEquals("EntryId ", j, entryId); - assertEquals("Entry Data ", expectedValue, new String(data)); - } - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EnableZkSecurityBasicTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EnableZkSecurityBasicTest.java deleted file mode 100644 index 67343a6e6f4..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EnableZkSecurityBasicTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2016 The Apache Software Foundation. - * - * Licensed 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. - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.util.BookKeeperConstants.READONLY; -import static org.junit.Assert.assertEquals; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.List; -import javax.security.auth.login.Configuration; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.data.ACL; -import org.apache.zookeeper.data.Stat; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * Test basic functions using secured ZooKeeper. - */ -public class EnableZkSecurityBasicTest extends BookKeeperClusterTestCase { - - public EnableZkSecurityBasicTest() { - super(0); - this.baseClientConf.setZkEnableSecurity(true); - this.baseConf.setZkEnableSecurity(true); - } - - @BeforeClass - public static void setupJAAS() throws IOException { - System.setProperty("zookeeper.authProvider.1", "org.apache.zookeeper.server.auth.SASLAuthenticationProvider"); - File tmpJaasDir = Files.createTempDirectory("jassTmpDir").toFile(); - File tmpJaasFile = new File(tmpJaasDir, "jaas.conf"); - String jassFileContent = "Server {\n" - + " org.apache.zookeeper.server.auth.DigestLoginModule required\n" - + " user_foo=\"bar\";\n" - + "};\n" - + "\n" - + "Client {\n" - + " org.apache.zookeeper.server.auth.DigestLoginModule required\n" - + " username=\"foo\"\n" - + " password=\"bar\";\n" - + "};"; - Files.write(tmpJaasFile.toPath(), jassFileContent.getBytes(StandardCharsets.UTF_8)); - System.setProperty("java.security.auth.login.config", tmpJaasFile.getAbsolutePath()); - Configuration.getConfiguration().refresh(); - } - - @AfterClass - public static void cleanUpJAAS() { - System.clearProperty("java.security.auth.login.config"); - Configuration.getConfiguration().refresh(); - System.clearProperty("zookeeper.authProvider.1"); - } - - @Test - public void testCreateLedgerAddEntryOnSecureZooKeepeer() throws Exception { - startNewBookie(); - - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setZkTimeout(20000); - - conf.setZkEnableSecurity(true); - - try (BookKeeper bkc = new BookKeeper(conf)) { - try (LedgerHandle lh = bkc.createLedger(1, 1, 1, BookKeeper.DigestType.CRC32, "testPasswd".getBytes())) { - lh.addEntry("foo".getBytes(StandardCharsets.UTF_8)); - } - } - - checkAllAcls(); - } - - private void checkAllAcls() throws IOException, InterruptedException, KeeperException { - ZooKeeper zk = ZooKeeperClient.newBuilder() - .connectString(zkUtil.getZooKeeperConnectString()) - .sessionTimeoutMs(20000) - .build(); - checkACls(zk, "/"); - zk.close(); - } - - private void checkACls(ZooKeeper zk, String path) throws KeeperException, InterruptedException { - List children = zk.getChildren(path, null); - for (String child : children) { - if (child.equals(READONLY)) { - continue; - } - - String fullPath = path.equals("/") ? path + child : path + "/" + child; - List acls = zk.getACL(fullPath, new Stat()); - checkACls(zk, fullPath); - - if (!fullPath.startsWith("/zookeeper") // skip zookeeper internal nodes - && !fullPath.equals("/ledgers") // node created by test setup - && !fullPath.equals("/ledgers/" + BookKeeperConstants.AVAILABLE_NODE) - && !fullPath.equals("/ledgers/" + BookKeeperConstants.INSTANCEID) // node created by test setup - ) { - assertEquals(1, acls.size()); - assertEquals(31, acls.get(0).getPerms()); - assertEquals(31, acls.get(0).getPerms()); - assertEquals("unexpected ACLS on " + fullPath + ": " + acls.get(0), "foo", acls.get(0).getId().getId()); - assertEquals("unexpected ACLS on " + fullPath + ": " + acls.get(0), "sasl", - acls.get(0).getId().getScheme()); - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EntryMemTableTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EntryMemTableTest.java deleted file mode 100644 index f2dbf643831..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EntryMemTableTest.java +++ /dev/null @@ -1,472 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.PrimitiveIterator.OfLong; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.Bookie.NoLedgerException; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * Test the EntryMemTable class. - */ -@Slf4j -@RunWith(Parameterized.class) -public class EntryMemTableTest implements CacheCallback, SkipListFlusher, CheckpointSource { - - private Class entryMemTableClass; - private EntryMemTable memTable; - private final Random random = new Random(); - private TestCheckPoint curCheckpoint = new TestCheckPoint(0, 0); - - @Parameters - public static Collection memTableClass() { - return Arrays.asList(new Object[][] { { EntryMemTable.class }, { EntryMemTableWithParallelFlusher.class } }); - } - - public EntryMemTableTest(Class entryMemTableClass) { - this.entryMemTableClass = entryMemTableClass; - } - - @Override - public Checkpoint newCheckpoint() { - return curCheckpoint; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) - throws IOException { - } - - @Before - public void setUp() throws Exception { - if (entryMemTableClass.equals(EntryMemTableWithParallelFlusher.class)) { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - this.memTable = new EntryMemTableWithParallelFlusher(conf, this, NullStatsLogger.INSTANCE); - } else { - this.memTable = new EntryMemTable(TestBKConfiguration.newServerConfiguration(), this, - NullStatsLogger.INSTANCE); - } - } - - @After - public void cleanup() throws Exception{ - this.memTable.close(); - } - - @Test - public void testLogMark() throws IOException { - LogMark mark = new LogMark(); - assertTrue(mark.compare(new LogMark()) == 0); - assertTrue(mark.compare(LogMark.MAX_VALUE) < 0); - mark.setLogMark(3, 11); - byte[] data = new byte[16]; - ByteBuffer buf = ByteBuffer.wrap(data); - mark.writeLogMark(buf); - buf.flip(); - LogMark mark1 = new LogMark(9, 13); - assertTrue(mark1.compare(mark) > 0); - mark1.readLogMark(buf); - assertTrue(mark1.compare(mark) == 0); - } - - /** - * Basic put/get. - * @throws IOException - * */ - @Test - public void testBasicOps() throws IOException { - long ledgerId = 1; - long entryId = 1; - byte[] data = new byte[10]; - random.nextBytes(data); - ByteBuffer buf = ByteBuffer.wrap(data); - memTable.addEntry(ledgerId, entryId, buf, this); - buf.rewind(); - EntryKeyValue kv = memTable.getEntry(ledgerId, entryId); - assertTrue(kv.getLedgerId() == ledgerId); - assertTrue(kv.getEntryId() == entryId); - assertTrue(kv.getValueAsByteBuffer().nioBuffer().equals(buf)); - memTable.flush(this); - } - - @Override - public void onSizeLimitReached(Checkpoint cp) throws IOException { - // No-op - } - - public void process(long ledgerId, long entryId, ByteBuf entry) - throws IOException { - // No-op - } - - /** - * Test read/write across snapshot. - * @throws IOException - */ - @Test - public void testScanAcrossSnapshot() throws IOException { - byte[] data = new byte[10]; - List keyValues = new ArrayList(); - for (long entryId = 1; entryId < 100; entryId++) { - for (long ledgerId = 1; ledgerId < 3; ledgerId++) { - random.nextBytes(data); - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this); - keyValues.add(memTable.getEntry(ledgerId, entryId)); - if (random.nextInt(16) == 0) { - memTable.snapshot(); - } - } - } - - for (EntryKeyValue kv : keyValues) { - assertTrue(memTable.getEntry(kv.getLedgerId(), kv.getEntryId()).equals(kv)); - } - memTable.flush(this, Checkpoint.MAX); - } - - private class KVFLusher implements SkipListFlusher { - final Set keyValues; - - KVFLusher(final Set keyValues) { - this.keyValues = keyValues; - } - - @Override - public void process(long ledgerId, long entryId, ByteBuf entry) throws IOException { - assertTrue(ledgerId + ":" + entryId + " is duplicate in store!", - keyValues.add(new EntryKeyValue(ledgerId, entryId, entry.array()))); - } - } - - private class NoLedgerFLusher implements SkipListFlusher { - @Override - public void process(long ledgerId, long entryId, ByteBuf entry) throws IOException { - throw new NoLedgerException(ledgerId); - } - } - - /** - * Test flush w/ logMark parameter. - * @throws IOException - */ - @Test - public void testFlushLogMark() throws IOException { - Set flushedKVs = Collections.newSetFromMap(new ConcurrentHashMap()); - KVFLusher flusher = new KVFLusher(flushedKVs); - - curCheckpoint.setCheckPoint(2, 2); - - byte[] data = new byte[10]; - long ledgerId = 100; - for (long entryId = 1; entryId < 100; entryId++) { - random.nextBytes(data); - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this); - } - - assertNull(memTable.snapshot(new TestCheckPoint(1, 1))); - assertNotNull(memTable.snapshot(new TestCheckPoint(3, 3))); - - assertTrue(0 < memTable.flush(flusher)); - assertTrue(0 == memTable.flush(flusher)); - - curCheckpoint.setCheckPoint(4, 4); - - random.nextBytes(data); - memTable.addEntry(ledgerId, 101, ByteBuffer.wrap(data), this); - assertTrue(0 == memTable.flush(flusher)); - - assertTrue(0 == memTable.flush(flusher, new TestCheckPoint(3, 3))); - assertTrue(0 < memTable.flush(flusher, new TestCheckPoint(4, 5))); - } - - /** - * Test snapshot/flush interaction. - * @throws IOException - */ - @Test - public void testFlushSnapshot() throws IOException { - HashSet keyValues = new HashSet(); - Set flushedKVs = Collections.newSetFromMap(new ConcurrentHashMap()); - KVFLusher flusher = new KVFLusher(flushedKVs); - - byte[] data = new byte[10]; - for (long entryId = 1; entryId < 100; entryId++) { - for (long ledgerId = 1; ledgerId < 100; ledgerId++) { - random.nextBytes(data); - assertTrue(ledgerId + ":" + entryId + " is duplicate in mem-table!", - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this) != 0); - assertTrue(ledgerId + ":" + entryId + " is duplicate in hash-set!", - keyValues.add(memTable.getEntry(ledgerId, entryId))); - if (random.nextInt(16) == 0) { - if (null != memTable.snapshot()) { - if (random.nextInt(2) == 0) { - memTable.flush(flusher); - } - } - } - } - } - - memTable.flush(flusher, Checkpoint.MAX); - for (EntryKeyValue kv : keyValues) { - assertTrue("kv " + kv.toString() + " was not flushed!", flushedKVs.contains(kv)); - } - } - - /** - * Test NoLedger exception/flush interaction. - * @throws IOException - */ - @Test - public void testNoLedgerException() throws IOException { - NoLedgerFLusher flusher = new NoLedgerFLusher(); - - byte[] data = new byte[10]; - for (long entryId = 1; entryId < 100; entryId++) { - for (long ledgerId = 1; ledgerId < 100; ledgerId++) { - random.nextBytes(data); - if (random.nextInt(16) == 0) { - if (null != memTable.snapshot()) { - memTable.flush(flusher); - } - } - } - } - - memTable.flush(flusher, Checkpoint.MAX); - } - - private static class TestCheckPoint implements Checkpoint { - - LogMark mark; - - public TestCheckPoint(long fid, long fpos) { - mark = new LogMark(fid, fpos); - } - - private void setCheckPoint(long fid, long fpos) { - mark.setLogMark(fid, fpos); - } - - @Override - public int compareTo(Checkpoint o) { - if (Checkpoint.MAX == o) { - return -1; - } - return mark.compare(((TestCheckPoint) o).mark); - } - - } - - @Test - public void testGetListOfEntriesOfLedger() throws IOException { - Set flushedKVs = Collections.newSetFromMap(new ConcurrentHashMap()); - KVFLusher flusher = new KVFLusher(flushedKVs); - int numofEntries = 100; - int numOfLedgers = 5; - byte[] data = new byte[10]; - for (long entryId = 1; entryId <= numofEntries; entryId++) { - for (long ledgerId = 1; ledgerId <= numOfLedgers; ledgerId++) { - random.nextBytes(data); - assertTrue(ledgerId + ":" + entryId + " is duplicate in mem-table!", - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this) != 0); - } - } - for (long ledgerId = 1; ledgerId <= numOfLedgers; ledgerId++) { - OfLong entriesItr = memTable.getListOfEntriesOfLedger((random.nextInt((int) ledgerId) + 1)); - ArrayList listOfEntries = new ArrayList(); - Consumer addMethod = listOfEntries::add; - entriesItr.forEachRemaining(addMethod); - assertEquals("Number of Entries", numofEntries, listOfEntries.size()); - for (int i = 0; i < numofEntries; i++) { - assertEquals("listOfEntries should be sorted", Long.valueOf(i + 1), listOfEntries.get(i)); - } - } - assertTrue("Snapshot is expected to be empty since snapshot is not done", memTable.snapshot.isEmpty()); - assertTrue("Take snapshot and returned checkpoint should not be empty", memTable.snapshot() != null); - assertFalse("After taking snapshot, snapshot should not be empty ", memTable.snapshot.isEmpty()); - for (long ledgerId = 1; ledgerId <= numOfLedgers; ledgerId++) { - OfLong entriesItr = memTable.getListOfEntriesOfLedger((random.nextInt((int) ledgerId) + 1)); - ArrayList listOfEntries = new ArrayList(); - Consumer addMethod = listOfEntries::add; - entriesItr.forEachRemaining(addMethod); - assertEquals("Number of Entries should be the same even after taking snapshot", numofEntries, - listOfEntries.size()); - for (int i = 0; i < numofEntries; i++) { - assertEquals("listOfEntries should be sorted", Long.valueOf(i + 1), listOfEntries.get(i)); - } - } - - memTable.flush(flusher); - for (long ledgerId = 1; ledgerId <= numOfLedgers; ledgerId++) { - OfLong entriesItr = memTable.getListOfEntriesOfLedger((random.nextInt((int) ledgerId) + 1)); - assertFalse("After flushing there shouldn't be entries in memtable", entriesItr.hasNext()); - } - } - - @Test - public void testGetListOfEntriesOfLedgerFromBothKVMapAndSnapshot() throws IOException { - int numofEntries = 100; - int newNumOfEntries = 200; - int numOfLedgers = 5; - byte[] data = new byte[10]; - for (long entryId = 1; entryId <= numofEntries; entryId++) { - for (long ledgerId = 1; ledgerId <= numOfLedgers; ledgerId++) { - random.nextBytes(data); - assertTrue(ledgerId + ":" + entryId + " is duplicate in mem-table!", - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this) != 0); - } - } - - assertTrue("Snapshot is expected to be empty since snapshot is not done", memTable.snapshot.isEmpty()); - assertTrue("Take snapshot and returned checkpoint should not be empty", memTable.snapshot() != null); - assertFalse("After taking snapshot, snapshot should not be empty ", memTable.snapshot.isEmpty()); - - for (long entryId = numofEntries + 1; entryId <= newNumOfEntries; entryId++) { - for (long ledgerId = 1; ledgerId <= numOfLedgers; ledgerId++) { - random.nextBytes(data); - assertTrue(ledgerId + ":" + entryId + " is duplicate in mem-table!", - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this) != 0); - } - } - - for (long ledgerId = 1; ledgerId <= numOfLedgers; ledgerId++) { - OfLong entriesItr = memTable.getListOfEntriesOfLedger((random.nextInt((int) ledgerId) + 1)); - ArrayList listOfEntries = new ArrayList(); - Consumer addMethod = listOfEntries::add; - entriesItr.forEachRemaining(addMethod); - assertEquals("Number of Entries should be the same", newNumOfEntries, listOfEntries.size()); - for (int i = 0; i < newNumOfEntries; i++) { - assertEquals("listOfEntries should be sorted", Long.valueOf(i + 1), listOfEntries.get(i)); - } - } - } - - @Test - public void testGetListOfEntriesOfLedgerWhileAddingConcurrently() throws IOException, InterruptedException { - final int numofEntries = 100; - final int newNumOfEntries = 200; - final int concurrentAddOfEntries = 300; - long ledgerId = 5; - byte[] data = new byte[10]; - for (long entryId = 1; entryId <= numofEntries; entryId++) { - random.nextBytes(data); - assertTrue(ledgerId + ":" + entryId + " is duplicate in mem-table!", - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this) != 0); - } - - assertTrue("Snapshot is expected to be empty since snapshot is not done", memTable.snapshot.isEmpty()); - assertTrue("Take snapshot and returned checkpoint should not be empty", memTable.snapshot() != null); - assertFalse("After taking snapshot, snapshot should not be empty ", memTable.snapshot.isEmpty()); - - for (long entryId = numofEntries + 1; entryId <= newNumOfEntries; entryId++) { - random.nextBytes(data); - assertTrue(ledgerId + ":" + entryId + " is duplicate in mem-table!", - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(data), this) != 0); - } - - AtomicBoolean successfullyAdded = new AtomicBoolean(true); - - Thread threadToAdd = new Thread(new Runnable() { - @Override - public void run() { - try { - for (long entryId = newNumOfEntries + 1; entryId <= concurrentAddOfEntries; entryId++) { - random.nextBytes(data); - boolean thisEntryAddedSuccessfully = (memTable.addEntry(ledgerId, entryId, - ByteBuffer.wrap(data), EntryMemTableTest.this) != 0); - successfullyAdded.set(successfullyAdded.get() && thisEntryAddedSuccessfully); - Thread.sleep(10); - } - } catch (IOException e) { - log.error("Got Unexpected exception while adding entries"); - successfullyAdded.set(false); - } catch (InterruptedException e) { - log.error("Got InterruptedException while waiting"); - successfullyAdded.set(false); - } - } - }); - threadToAdd.start(); - - Thread.sleep(200); - OfLong entriesItr = memTable.getListOfEntriesOfLedger(ledgerId); - ArrayList listOfEntries = new ArrayList(); - while (entriesItr.hasNext()) { - listOfEntries.add(entriesItr.next()); - Thread.sleep(5); - } - threadToAdd.join(5000); - assertTrue("Entries should be added successfully in the spawned thread", successfullyAdded.get()); - - for (int i = 0; i < newNumOfEntries; i++) { - assertEquals("listOfEntries should be sorted", Long.valueOf(i + 1), listOfEntries.get(i)); - } - } - - @Test - public void testAddSameEntries() throws IOException { - final long ledgerId = 1; - final long entryId = 1; - final int size = 10; - final byte[] bytes = new byte[size]; - final int initialPermits = memTable.skipListSemaphore.availablePermits(); - - for (int i = 0; i < 5; i++) { - memTable.addEntry(ledgerId, entryId, ByteBuffer.wrap(bytes), this); - assertEquals(memTable.kvmap.size(), 1); - assertEquals(memTable.skipListSemaphore.availablePermits(), initialPermits - size); - } - - memTable.snapshot(Checkpoint.MAX); - memTable.flush(this); - assertEquals(memTable.kvmap.size(), 0); - assertEquals(memTable.skipListSemaphore.availablePermits(), initialPermits); - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/FileInfoBackingCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/FileInfoBackingCacheTest.java deleted file mode 100644 index e7d27ea8a80..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/FileInfoBackingCacheTest.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalNotification; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.io.File; -import java.io.IOException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.FileInfoBackingCache.CachedFileInfo; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Tests for FileInfoBackingCache. - */ -@Slf4j -public class FileInfoBackingCacheTest { - final byte[] masterKey = new byte[0]; - final File baseDir; - final ThreadFactory threadFactory = new ThreadFactoryBuilder() - .setNameFormat("backing-cache-test-%d").setDaemon(true).build(); - ExecutorService executor; - - public FileInfoBackingCacheTest() throws Exception { - baseDir = File.createTempFile("foo", "bar"); - } - - @Before - public void setup() throws Exception { - Assert.assertTrue(baseDir.delete()); - Assert.assertTrue(baseDir.mkdirs()); - baseDir.deleteOnExit(); - - executor = Executors.newCachedThreadPool(threadFactory); - } - - @After - public void tearDown() throws Exception { - if (executor != null) { - executor.shutdown(); - } - } - - @Test(timeout = 30000) - public void basicTest() throws Exception { - FileInfoBackingCache cache = new FileInfoBackingCache( - (ledgerId, createIfNotFound) -> { - File f = new File(baseDir, String.valueOf(ledgerId)); - f.deleteOnExit(); - return f; - }, FileInfo.CURRENT_HEADER_VERSION); - CachedFileInfo fi = cache.loadFileInfo(1, masterKey); - Assert.assertEquals(fi.getRefCount(), 1); - CachedFileInfo fi2 = cache.loadFileInfo(2, masterKey); - Assert.assertEquals(fi2.getRefCount(), 1); - CachedFileInfo fi3 = cache.loadFileInfo(1, null); - Assert.assertEquals(fi, fi3); - Assert.assertEquals(fi3.getRefCount(), 2); - - // check that it expires correctly - fi.release(); - fi3.release(); - - Assert.assertEquals(fi.getRefCount(), FileInfoBackingCache.DEAD_REF); - CachedFileInfo fi4 = cache.loadFileInfo(1, null); - Assert.assertFalse(fi4 == fi); - Assert.assertEquals(fi.getRefCount(), FileInfoBackingCache.DEAD_REF); - Assert.assertEquals(fi4.getRefCount(), 1); - Assert.assertEquals(fi.getLf(), fi4.getLf()); - } - - @Test(expected = IOException.class, timeout = 30000) - public void testNoKey() throws Exception { - FileInfoBackingCache cache = new FileInfoBackingCache( - (ledgerId, createIfNotFound) -> { - Assert.assertFalse(createIfNotFound); - throw new Bookie.NoLedgerException(ledgerId); - }, FileInfo.CURRENT_HEADER_VERSION); - cache.loadFileInfo(1, null); - } - - /** - * Of course this can't prove they don't exist, but - * try to shake them out none the less. - */ - @Test(timeout = 30000) - public void testForDeadlocks() throws Exception { - int numRunners = 20; - int maxLedgerId = 10; - AtomicBoolean done = new AtomicBoolean(false); - - FileInfoBackingCache cache = new FileInfoBackingCache( - (ledgerId, createIfNotFound) -> { - File f = new File(baseDir, String.valueOf(ledgerId)); - f.deleteOnExit(); - return f; - }, FileInfo.CURRENT_HEADER_VERSION); - Iterable>> futures = - IntStream.range(0, numRunners).mapToObj( - (i) -> { - Callable> c = () -> { - Random r = new Random(); - List fileInfos = new ArrayList<>(); - Set allFileInfos = new HashSet<>(); - while (!done.get()) { - if (r.nextBoolean() && fileInfos.size() < 5) { // take a reference - CachedFileInfo fi = cache.loadFileInfo(r.nextInt(maxLedgerId), masterKey); - Assert.assertFalse(fi.isClosed()); - allFileInfos.add(fi); - fileInfos.add(fi); - } else { // release a reference - Collections.shuffle(fileInfos); - if (!fileInfos.isEmpty()) { - fileInfos.remove(0).release(); - } - } - } - for (CachedFileInfo fi : fileInfos) { - Assert.assertFalse(fi.isClosed()); - fi.release(); - } - return allFileInfos; - }; - return executor.submit(c); - }).collect(Collectors.toList()); - Thread.sleep(TimeUnit.SECONDS.toMillis(10)); - done.set(true); - - // ensure all threads are finished operating on cache, before checking any - for (Future> f : futures) { - f.get(); - } - - for (Future> f : futures) { - for (CachedFileInfo fi : f.get()) { - Assert.assertTrue(fi.isClosed()); - Assert.assertEquals(FileInfoBackingCache.DEAD_REF, fi.getRefCount()); - } - } - - // try to load all ledgers again. - // They should be loaded fresh (i.e. this load should be only reference) - for (int i = 0; i < maxLedgerId; i++) { - Assert.assertEquals(1, cache.loadFileInfo(i, masterKey).getRefCount()); - } - } - - @Test(timeout = 30000) - public void testRefCountRace() throws Exception { - AtomicBoolean done = new AtomicBoolean(false); - FileInfoBackingCache cache = new FileInfoBackingCache( - (ledgerId, createIfNotFound) -> { - File f = new File(baseDir, String.valueOf(ledgerId)); - f.deleteOnExit(); - return f; - }, FileInfo.CURRENT_HEADER_VERSION); - - Iterable>> futures = - IntStream.range(0, 2).mapToObj( - (i) -> { - Callable> c = () -> { - Set allFileInfos = new HashSet<>(); - while (!done.get()) { - CachedFileInfo fi = cache.loadFileInfo(1, masterKey); - Assert.assertFalse(fi.isClosed()); - allFileInfos.add(fi); - fi.release(); - } - return allFileInfos; - }; - return executor.submit(c); - }).collect(Collectors.toList()); - Thread.sleep(TimeUnit.SECONDS.toMillis(10)); - done.set(true); - - // ensure all threads are finished operating on cache, before checking any - for (Future> f : futures) { - f.get(); - } - - for (Future> f : futures) { - for (CachedFileInfo fi : f.get()) { - Assert.assertTrue(fi.isClosed()); - Assert.assertEquals(FileInfoBackingCache.DEAD_REF, fi.getRefCount()); - } - } - } - - private void guavaEvictionListener(RemovalNotification notification) { - notification.getValue().release(); - } - - @Test(timeout = 30000) - public void testRaceGuavaEvictAndReleaseBeforeRetain() throws Exception { - AtomicBoolean done = new AtomicBoolean(false); - Random random = new SecureRandom(); - FileInfoBackingCache cache = new FileInfoBackingCache( - (ledgerId, createIfNotFound) -> { - File f = new File(baseDir, String.valueOf(ledgerId)); - f.deleteOnExit(); - return f; - }, FileInfo.CURRENT_HEADER_VERSION); - - Cache guavaCache = CacheBuilder.newBuilder() - .maximumSize(1) - .removalListener(this::guavaEvictionListener) - .build(); - - Iterable>> futures = - LongStream.range(0L, 2L).mapToObj( - (i) -> { - Callable> c = () -> { - Set allFileInfos = new HashSet<>(); - while (!done.get()) { - CachedFileInfo fi = null; - - do { - fi = guavaCache.get( - i, () -> cache.loadFileInfo(i, masterKey)); - allFileInfos.add(fi); - Thread.sleep(random.nextInt(100)); - } while (!fi.tryRetain()); - - Assert.assertFalse(fi.isClosed()); - fi.release(); - } - return allFileInfos; - }; - return executor.submit(c); - }).collect(Collectors.toList()); - Thread.sleep(TimeUnit.SECONDS.toMillis(10)); - done.set(true); - - // ensure all threads are finished operating on cache, before checking any - for (Future> f : futures) { - f.get(); - } - guavaCache.invalidateAll(); - - for (Future> f : futures) { - for (CachedFileInfo fi : f.get()) { - Assert.assertTrue(fi.isClosed()); - Assert.assertEquals(FileInfoBackingCache.DEAD_REF, fi.getRefCount()); - } - } - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ForceAuditorChecksCmdTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ForceAuditorChecksCmdTest.java deleted file mode 100644 index 18785a58b48..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ForceAuditorChecksCmdTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; - -import com.google.common.util.concurrent.UncheckedExecutionException; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.replication.ReplicationException; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assert; -import org.junit.Test; - - -/** - * Integration test of {@link BookieShell.TriggerAuditCmd}. - */ -public class ForceAuditorChecksCmdTest extends BookKeeperClusterTestCase { - - public ForceAuditorChecksCmdTest() { - super(1); - baseConf.setAuditorPeriodicPlacementPolicyCheckInterval(10000); - baseConf.setAuditorPeriodicReplicasCheckInterval(10000); - } - - /** - * Verify that the auditor checks last execution time (stored in zookeeper) is reset to an older value - * when triggeraudit command is run with certain parameters. Rebooting the auditor after this would - * result in immediate run of audit checks. - */ - @Test - public void verifyAuditCTimeReset() throws Exception { - String[] argv = new String[] { "forceauditchecks", "-calc", "-ppc", "-rc" }; - long curTime = System.currentTimeMillis(); - - final ServerConfiguration conf = confByIndex(0); - BookieShell bkShell = new BookieShell(); - bkShell.setConf(conf); - - // Add dummy last execution time for audit checks - runFunctionWithLedgerManagerFactory(conf, mFactory -> { - try (LedgerUnderreplicationManager urM = - mFactory.newLedgerUnderreplicationManager()) { - urM.setCheckAllLedgersCTime(curTime); - urM.setPlacementPolicyCheckCTime(curTime); - urM.setReplicasCheckCTime(curTime); - } catch (InterruptedException | ReplicationException e) { - throw new UncheckedExecutionException(e); - } - return null; - }); - - // Run the actual shell command - Assert.assertEquals("Failed to return exit code!", 0, bkShell.run(argv)); - - // Verify that the time has been reset to an older value (at least 20 days) - runFunctionWithLedgerManagerFactory(conf, mFactory -> { - try (LedgerUnderreplicationManager urm = - mFactory.newLedgerUnderreplicationManager()) { - long checkAllLedgersCTime = urm.getCheckAllLedgersCTime(); - if (checkAllLedgersCTime > (curTime - (20 * 24 * 60 * 60 * 1000))) { - Assert.fail("The checkAllLedgersCTime should have been reset to atleast 20 days old"); - } - long placementPolicyCheckCTime = urm.getPlacementPolicyCheckCTime(); - if (placementPolicyCheckCTime > (curTime - (20 * 24 * 60 * 60 * 1000))) { - Assert.fail("The placementPolicyCheckCTime should have been reset to atleast 20 days old"); - } - long replicasCheckCTime = urm.getReplicasCheckCTime(); - if (replicasCheckCTime > (curTime - (20 * 24 * 60 * 60 * 1000))) { - Assert.fail("The replicasCheckCTime should have been reset to atleast 20 days old"); - } - } catch (InterruptedException | ReplicationException e) { - throw new UncheckedExecutionException(e); - } - return null; - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GarbageCollectorThreadTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GarbageCollectorThreadTest.java deleted file mode 100644 index 01d7e80f10c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GarbageCollectorThreadTest.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.logIdFromLocation; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.makeEntry; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newDirectEntryLogger; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newDirsManager; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newLegacyEntryLogger; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.openMocks; - -import java.io.File; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.bookie.storage.EntryLogger; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.MockLedgerManager; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; - -/** - * Unit test for {@link GarbageCollectorThread}. - */ -@SuppressWarnings("deprecation") -public class GarbageCollectorThreadTest { - private static final Slogger slog = Slogger.CONSOLE; - - private final TmpDirs tmpDirs = new TmpDirs(); - - @InjectMocks - @Spy - private GarbageCollectorThread mockGCThread; - - @Mock - private LedgerManager ledgerManager; - @Mock - private StatsLogger statsLogger; - @Mock - private ScheduledExecutorService gcExecutor; - - private ServerConfiguration conf = spy(new ServerConfiguration().setAllowLoopback(true)); - private CompactableLedgerStorage ledgerStorage = mock(CompactableLedgerStorage.class); - - @Before - public void setUp() throws Exception { - conf.setAllowLoopback(true); - openMocks(this); - } - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - } - - @Test - public void testCompactEntryLogWithException() throws Exception { - AbstractLogCompactor mockCompactor = mock(AbstractLogCompactor.class); - when(mockCompactor.compact(any(EntryLogMetadata.class))) - .thenThrow(new RuntimeException("Unexpected compaction error")); - mockGCThread.compactor = mockCompactor; - - // Although compaction of an entry log fails due to an unexpected error, - // the `compacting` flag should return to false - AtomicBoolean compacting = mockGCThread.compacting; - assertFalse(compacting.get()); - mockGCThread.compactEntryLog(new EntryLogMetadata(9999)); - assertFalse(compacting.get()); - } - - @Test - public void testCalculateUsageBucket() { - // Valid range for usage is [0.0 to 1.0] - final int numBuckets = 10; - int[] usageBuckets = new int[numBuckets]; - String[] bucketNames = new String[numBuckets]; - for (int i = 0; i < numBuckets; i++) { - usageBuckets[i] = 0; - bucketNames[i] = String.format("%d%%", (i + 1) * 10); - } - - int items = 10000; - - for (int item = 0; item <= items; item++) { - double usage = ((double) item / (double) items); - int index = mockGCThread.calculateUsageIndex(numBuckets, usage); - assertFalse("Boundary condition exceeded", index < 0 || index >= numBuckets); - slog.kv("usage", usage) - .kv("index", index) - .info("Mapped usage to index"); - usageBuckets[index]++; - } - - Slogger sl = slog.ctx(); - for (int i = 0; i < numBuckets; i++) { - sl = sl.kv(bucketNames[i], usageBuckets[i]); - } - sl.info("Compaction: entry log usage buckets"); - - int sum = 0; - for (int i = 0; i < numBuckets; i++) { - sum += usageBuckets[i]; - } - Assert.assertEquals("Incorrect number of items", items + 1, sum); - } - - @Test - public void testExtractMetaFromEntryLogsLegacy() throws Exception { - File ledgerDir = tmpDirs.createNew("testExtractMeta", "ledgers"); - testExtractMetaFromEntryLogs( - newLegacyEntryLogger(20000, ledgerDir), ledgerDir); - } - - @Test - public void testExtractMetaFromEntryLogsDirect() throws Exception { - File ledgerDir = tmpDirs.createNew("testExtractMeta", "ledgers"); - testExtractMetaFromEntryLogs( - newDirectEntryLogger(23000, // direct header is 4kb rather than 1kb - ledgerDir), ledgerDir); - } - - private void testExtractMetaFromEntryLogs(EntryLogger entryLogger, File ledgerDir) - throws Exception { - - MockLedgerStorage storage = new MockLedgerStorage(); - MockLedgerManager lm = new MockLedgerManager(); - - GarbageCollectorThread gcThread = new GarbageCollectorThread( - TestBKConfiguration.newServerConfiguration(), lm, - newDirsManager(ledgerDir), - storage, entryLogger, - NullStatsLogger.INSTANCE); - - // Add entries. - // Ledger 1 is on first entry log - // Ledger 2 spans first, second and third entry log - // Ledger 3 is on the third entry log (which is still active when extract meta) - long loc1 = entryLogger.addEntry(1L, makeEntry(1L, 1L, 5000)); - long loc2 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 5000)); - assertThat(logIdFromLocation(loc2), equalTo(logIdFromLocation(loc1))); - long loc3 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 15000)); - assertThat(logIdFromLocation(loc3), greaterThan(logIdFromLocation(loc2))); - long loc4 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 15000)); - assertThat(logIdFromLocation(loc4), greaterThan(logIdFromLocation(loc3))); - long loc5 = entryLogger.addEntry(3L, makeEntry(3L, 1L, 1000)); - assertThat(logIdFromLocation(loc5), equalTo(logIdFromLocation(loc4))); - - long logId1 = logIdFromLocation(loc2); - long logId2 = logIdFromLocation(loc3); - long logId3 = logIdFromLocation(loc5); - entryLogger.flush(); - - storage.setMasterKey(1L, new byte[0]); - storage.setMasterKey(2L, new byte[0]); - storage.setMasterKey(3L, new byte[0]); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2)); - assertTrue(entryLogger.logExists(logId3)); - - // all ledgers exist, nothing should disappear - final EntryLogMetadataMap entryLogMetaMap = gcThread.getEntryLogMetaMap(); - gcThread.extractMetaFromEntryLogs(); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2)); - assertTrue(entryLogMetaMap.containsKey(logId1)); - assertTrue(entryLogMetaMap.containsKey(logId2)); - assertTrue(entryLogger.logExists(logId3)); - - // log 2 is 100% ledger 2, so it should disappear if ledger 2 is deleted - entryLogMetaMap.clear(); - storage.deleteLedger(2L); - gcThread.extractMetaFromEntryLogs(); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1)); - assertTrue(entryLogMetaMap.containsKey(logId1)); - assertTrue(entryLogger.logExists(logId3)); - - // delete all ledgers, all logs except the current should be deleted - entryLogMetaMap.clear(); - storage.deleteLedger(1L); - storage.deleteLedger(3L); - gcThread.extractMetaFromEntryLogs(); - - assertThat(entryLogger.getFlushedLogIds(), empty()); - assertTrue(entryLogMetaMap.isEmpty()); - assertTrue(entryLogger.logExists(logId3)); - - // add enough entries to roll log, log 3 can not be GC'd - long loc6 = entryLogger.addEntry(3L, makeEntry(3L, 1L, 25000)); - assertThat(logIdFromLocation(loc6), greaterThan(logIdFromLocation(loc5))); - entryLogger.flush(); - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId3)); - - entryLogMetaMap.clear(); - gcThread.extractMetaFromEntryLogs(); - - assertThat(entryLogger.getFlushedLogIds(), empty()); - assertTrue(entryLogMetaMap.isEmpty()); - assertFalse(entryLogger.logExists(logId3)); - } - - @Test - public void testCompactionWithFileSizeCheck() throws Exception { - File ledgerDir = tmpDirs.createNew("testFileSize", "ledgers"); - EntryLogger entryLogger = newLegacyEntryLogger(20000, ledgerDir); - - MockLedgerStorage storage = new MockLedgerStorage(); - MockLedgerManager lm = new MockLedgerManager(); - - GarbageCollectorThread gcThread = new GarbageCollectorThread( - TestBKConfiguration.newServerConfiguration().setUseTargetEntryLogSizeForGc(true), lm, - newDirsManager(ledgerDir), - storage, entryLogger, NullStatsLogger.INSTANCE); - - // Add entries. - // Ledger 1 is on first entry log - // Ledger 2 spans first, second and third entry log - // Ledger 3 is on the third entry log (which is still active when extract meta) - long loc1 = entryLogger.addEntry(1L, makeEntry(1L, 1L, 5000)); - long loc2 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 5000)); - assertThat(logIdFromLocation(loc2), equalTo(logIdFromLocation(loc1))); - long loc3 = entryLogger.addEntry(2L, makeEntry(2L, 2L, 15000)); - assertThat(logIdFromLocation(loc3), greaterThan(logIdFromLocation(loc2))); - long loc4 = entryLogger.addEntry(2L, makeEntry(2L, 3L, 15000)); - assertThat(logIdFromLocation(loc4), greaterThan(logIdFromLocation(loc3))); - long loc5 = entryLogger.addEntry(3L, makeEntry(3L, 1L, 1000)); - assertThat(logIdFromLocation(loc5), equalTo(logIdFromLocation(loc4))); - long loc6 = entryLogger.addEntry(3L, makeEntry(3L, 2L, 5000)); - - long logId1 = logIdFromLocation(loc2); - long logId2 = logIdFromLocation(loc3); - long logId3 = logIdFromLocation(loc5); - long logId4 = logIdFromLocation(loc6); - entryLogger.flush(); - - storage.setMasterKey(1L, new byte[0]); - storage.setMasterKey(2L, new byte[0]); - storage.setMasterKey(3L, new byte[0]); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2, logId3)); - assertTrue(entryLogger.logExists(logId1)); - assertTrue(entryLogger.logExists(logId2)); - assertTrue(entryLogger.logExists(logId3)); - assertTrue(entryLogger.logExists(logId4)); - - // all ledgers exist, nothing should disappear - final EntryLogMetadataMap entryLogMetaMap = gcThread.getEntryLogMetaMap(); - gcThread.extractMetaFromEntryLogs(); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2, logId3)); - assertTrue(entryLogMetaMap.containsKey(logId1)); - assertTrue(entryLogMetaMap.containsKey(logId2)); - assertTrue(entryLogger.logExists(logId3)); - - storage.deleteLedger(1); - // only logId 1 will be compacted. - gcThread.runWithFlags(true, true, false); - - // logId1 and logId2 should be compacted - assertFalse(entryLogger.logExists(logId1)); - assertTrue(entryLogger.logExists(logId2)); - assertTrue(entryLogger.logExists(logId3)); - assertFalse(entryLogMetaMap.containsKey(logId1)); - assertTrue(entryLogMetaMap.containsKey(logId2)); - - assertEquals(1, storage.getUpdatedLocations().size()); - - EntryLocation location2 = storage.getUpdatedLocations().get(0); - assertEquals(2, location2.getLedger()); - assertEquals(1, location2.getEntry()); - assertEquals(logIdFromLocation(location2.getLocation()), logId4); - } - - @Test - public void testCompactionWithoutFileSizeCheck() throws Exception { - File ledgerDir = tmpDirs.createNew("testFileSize", "ledgers"); - EntryLogger entryLogger = newLegacyEntryLogger(20000, ledgerDir); - - MockLedgerStorage storage = new MockLedgerStorage(); - MockLedgerManager lm = new MockLedgerManager(); - - GarbageCollectorThread gcThread = new GarbageCollectorThread( - TestBKConfiguration.newServerConfiguration(), lm, - newDirsManager(ledgerDir), - storage, entryLogger, NullStatsLogger.INSTANCE); - - // Add entries. - // Ledger 1 is on first entry log - // Ledger 2 spans first, second and third entry log - // Ledger 3 is on the third entry log (which is still active when extract meta) - long loc1 = entryLogger.addEntry(1L, makeEntry(1L, 1L, 5000)); - long loc2 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 5000)); - assertThat(logIdFromLocation(loc2), equalTo(logIdFromLocation(loc1))); - long loc3 = entryLogger.addEntry(2L, makeEntry(2L, 2L, 15000)); - assertThat(logIdFromLocation(loc3), greaterThan(logIdFromLocation(loc2))); - long loc4 = entryLogger.addEntry(2L, makeEntry(2L, 3L, 15000)); - assertThat(logIdFromLocation(loc4), greaterThan(logIdFromLocation(loc3))); - long loc5 = entryLogger.addEntry(3L, makeEntry(3L, 1L, 1000)); - assertThat(logIdFromLocation(loc5), equalTo(logIdFromLocation(loc4))); - - long logId1 = logIdFromLocation(loc2); - long logId2 = logIdFromLocation(loc3); - long logId3 = logIdFromLocation(loc5); - entryLogger.flush(); - - storage.setMasterKey(1L, new byte[0]); - storage.setMasterKey(2L, new byte[0]); - storage.setMasterKey(3L, new byte[0]); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2)); - assertTrue(entryLogger.logExists(logId1)); - assertTrue(entryLogger.logExists(logId2)); - assertTrue(entryLogger.logExists(logId3)); - - // all ledgers exist, nothing should disappear - final EntryLogMetadataMap entryLogMetaMap = gcThread.getEntryLogMetaMap(); - gcThread.extractMetaFromEntryLogs(); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2)); - assertTrue(entryLogMetaMap.containsKey(logId1)); - assertTrue(entryLogMetaMap.containsKey(logId2)); - assertTrue(entryLogger.logExists(logId3)); - - gcThread.runWithFlags(true, true, false); - - assertTrue(entryLogger.logExists(logId1)); - assertTrue(entryLogger.logExists(logId2)); - assertTrue(entryLogger.logExists(logId3)); - assertTrue(entryLogMetaMap.containsKey(logId1)); - assertTrue(entryLogMetaMap.containsKey(logId2)); - - assertEquals(0, storage.getUpdatedLocations().size()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GcOverreplicatedLedgerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GcOverreplicatedLedgerTest.java deleted file mode 100644 index 6c17bd68c0a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GcOverreplicatedLedgerTest.java +++ /dev/null @@ -1,224 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import com.google.common.collect.Lists; -import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.SortedMap; -import java.util.concurrent.TimeUnit; -import lombok.Cleanup; -import org.apache.bookkeeper.bookie.GarbageCollector.GarbageCleaner; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerManagerTestCase; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.exceptions.MetadataException; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.SnapshotMap; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.zookeeper.ZooDefs; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * Test GC-overreplicated ledger. - */ -@RunWith(Parameterized.class) -public class GcOverreplicatedLedgerTest extends LedgerManagerTestCase { - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - ledgerManager = ledgerManagerFactory.newLedgerManager(); - activeLedgers = new SnapshotMap(); - } - - public GcOverreplicatedLedgerTest(Class lmFactoryCls) { - super(lmFactoryCls, 3); - } - - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { { HierarchicalLedgerManagerFactory.class } }); - } - - @Test - public void testGcOverreplicatedLedger() throws Exception { - LedgerHandle lh = bkc.createLedger(2, 2, DigestType.MAC, "".getBytes()); - activeLedgers.put(lh.getId(), true); - - LedgerMetadata newLedgerMetadata = ledgerManager.readLedgerMetadata(lh.getId()).get().getValue(); - - BookieId bookieNotInEnsemble = getBookieNotInEnsemble(newLedgerMetadata); - ServerConfiguration bkConf = getBkConf(bookieNotInEnsemble); - - @Cleanup - final MetadataBookieDriver metadataDriver = instantiateMetadataDriver(bkConf); - @Cleanup - final LedgerManagerFactory lmf = metadataDriver.getLedgerManagerFactory(); - @Cleanup - final LedgerUnderreplicationManager lum = lmf.newLedgerUnderreplicationManager(); - - Assert.assertFalse(lum.isLedgerBeingReplicated(lh.getId())); - - bkConf.setGcOverreplicatedLedgerWaitTime(10, TimeUnit.MILLISECONDS); - - lh.close(); - - final CompactableLedgerStorage mockLedgerStorage = new MockLedgerStorage(); - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(ledgerManager, mockLedgerStorage, - bkConf, NullStatsLogger.INSTANCE); - Thread.sleep(bkConf.getGcOverreplicatedLedgerWaitTimeMillis() + 1); - garbageCollector.gc(new GarbageCleaner() { - - @Override - public void clean(long ledgerId) { - try { - mockLedgerStorage.deleteLedger(ledgerId); - } catch (IOException e) { - e.printStackTrace(); - return; - } - } - }); - - Assert.assertFalse(lum.isLedgerBeingReplicated(lh.getId())); - Assert.assertFalse(activeLedgers.containsKey(lh.getId())); - } - - private static MetadataBookieDriver instantiateMetadataDriver(ServerConfiguration conf) - throws BookieException { - try { - final String metadataServiceUriStr = conf.getMetadataServiceUri(); - final MetadataBookieDriver driver = MetadataDrivers.getBookieDriver(URI.create(metadataServiceUriStr)); - driver.initialize(conf, NullStatsLogger.INSTANCE); - return driver; - } catch (MetadataException me) { - throw new BookieException.MetadataStoreException("Failed to initialize metadata bookie driver", me); - } catch (ConfigurationException e) { - throw new BookieException.BookieIllegalOpException(e); - } - } - - @Test - public void testNoGcOfLedger() throws Exception { - LedgerHandle lh = bkc.createLedger(2, 2, DigestType.MAC, "".getBytes()); - activeLedgers.put(lh.getId(), true); - - LedgerMetadata newLedgerMetadata = ledgerManager.readLedgerMetadata(lh.getId()).get().getValue(); - BookieId address = null; - SortedMap> ensembleMap = newLedgerMetadata.getAllEnsembles(); - for (List ensemble : ensembleMap.values()) { - address = ensemble.get(0); - } - ServerConfiguration bkConf = getBkConf(address); - bkConf.setGcOverreplicatedLedgerWaitTime(10, TimeUnit.MILLISECONDS); - - lh.close(); - - final CompactableLedgerStorage mockLedgerStorage = new MockLedgerStorage(); - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(ledgerManager, mockLedgerStorage, - bkConf, NullStatsLogger.INSTANCE); - Thread.sleep(bkConf.getGcOverreplicatedLedgerWaitTimeMillis() + 1); - garbageCollector.gc(new GarbageCleaner() { - - @Override - public void clean(long ledgerId) { - try { - mockLedgerStorage.deleteLedger(ledgerId); - } catch (IOException e) { - e.printStackTrace(); - return; - } - } - }); - - Assert.assertTrue(activeLedgers.containsKey(lh.getId())); - } - - @Test - public void testNoGcIfLedgerBeingReplicated() throws Exception { - LedgerHandle lh = bkc.createLedger(2, 2, DigestType.MAC, "".getBytes()); - activeLedgers.put(lh.getId(), true); - - LedgerMetadata newLedgerMetadata = ledgerManager.readLedgerMetadata(lh.getId()).get().getValue(); - BookieId bookieNotInEnsemble = getBookieNotInEnsemble(newLedgerMetadata); - ServerConfiguration bkConf = getBkConf(bookieNotInEnsemble); - bkConf.setGcOverreplicatedLedgerWaitTime(10, TimeUnit.MILLISECONDS); - - lh.close(); - - ZkLedgerUnderreplicationManager.acquireUnderreplicatedLedgerLock( - zkc, - ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf), - lh.getId(), - ZooDefs.Ids.OPEN_ACL_UNSAFE); - - final CompactableLedgerStorage mockLedgerStorage = new MockLedgerStorage(); - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(ledgerManager, mockLedgerStorage, - bkConf, NullStatsLogger.INSTANCE); - Thread.sleep(bkConf.getGcOverreplicatedLedgerWaitTimeMillis() + 1); - garbageCollector.gc(new GarbageCleaner() { - - @Override - public void clean(long ledgerId) { - try { - mockLedgerStorage.deleteLedger(ledgerId); - } catch (IOException e) { - e.printStackTrace(); - return; - } - } - }); - - Assert.assertTrue(activeLedgers.containsKey(lh.getId())); - } - - private BookieId getBookieNotInEnsemble(LedgerMetadata ledgerMetadata) throws Exception { - List allAddresses = Lists.newArrayList(); - allAddresses.addAll(bookieAddresses()); - SortedMap> ensembles = ledgerMetadata.getAllEnsembles(); - for (List fragmentEnsembles : ensembles.values()) { - allAddresses.removeAll(fragmentEnsembles); - } - Assert.assertEquals(allAddresses.size(), 1); - return allAddresses.get(0); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexCorruptionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexCorruptionTest.java deleted file mode 100644 index 492c37d60eb..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexCorruptionTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.Enumeration; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class tests that index corruption cases. - */ -public class IndexCorruptionTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(IndexCorruptionTest.class); - - DigestType digestType; - - int pageSize = 1024; - - public IndexCorruptionTest() { - super(1); - this.digestType = DigestType.CRC32; - baseConf.setPageSize(pageSize); - } - - @Test - public void testNoSuchLedger() throws Exception { - if (LOG.isDebugEnabled()) { - LOG.debug("Testing NoSuchLedger"); - } - - SyncThread syncThread = ((BookieImpl) serverByIndex(0).getBookie()).syncThread; - syncThread.suspendSync(); - // Create a ledger - LedgerHandle lh = bkc.createLedger(1, 1, digestType, "".getBytes()); - - // Close the ledger which cause a readEntry(0) call - LedgerHandle newLh = bkc.openLedger(lh.getId(), digestType, "".getBytes()); - - // Create a new ledger to write entries - String dummyMsg = "NoSuchLedger"; - int numMsgs = 3; - LedgerHandle wlh = bkc.createLedger(1, 1, digestType, "".getBytes()); - for (int i = 0; i < numMsgs; i++) { - wlh.addEntry(dummyMsg.getBytes()); - } - - syncThread.resumeSync(); - - // trigger sync - Thread.sleep(2 * baseConf.getFlushInterval()); - - // restart bookies - restartBookies(); - - Enumeration seq = wlh.readEntries(0, numMsgs - 1); - assertTrue("Enumeration of ledger entries has no element", seq.hasMoreElements()); - int entryId = 0; - while (seq.hasMoreElements()) { - LedgerEntry e = seq.nextElement(); - assertEquals(entryId, e.getEntryId()); - - assertArrayEquals(dummyMsg.getBytes(), e.getEntry()); - ++entryId; - } - assertEquals(entryId, numMsgs); - } - - @Test - public void testEmptyIndexPage() throws Exception { - if (LOG.isDebugEnabled()) { - LOG.debug("Testing EmptyIndexPage"); - } - - SyncThread syncThread = ((BookieImpl) serverByIndex(0).getBookie()).syncThread; - assertNotNull("Not found SyncThread.", syncThread); - - syncThread.suspendSync(); - - // Create a ledger - LedgerHandle lh1 = bkc.createLedger(1, 1, digestType, "".getBytes()); - - String dummyMsg = "NoSuchLedger"; - - // write two page entries to ledger 2 - int numMsgs = 2 * pageSize / 8; - LedgerHandle lh2 = bkc.createLedger(1, 1, digestType, "".getBytes()); - for (int i = 0; i < numMsgs; i++) { - lh2.addEntry(dummyMsg.getBytes()); - } - - syncThread.resumeSync(); - - // trigger sync - Thread.sleep(2 * baseConf.getFlushInterval()); - - syncThread.suspendSync(); - - // Close ledger 1 which cause a readEntry(0) call - LedgerHandle newLh1 = bkc.openLedger(lh1.getId(), digestType, "".getBytes()); - - // write another 3 entries to ledger 2 - for (int i = 0; i < 3; i++) { - lh2.addEntry(dummyMsg.getBytes()); - } - - syncThread.resumeSync(); - - // wait for sync again - Thread.sleep(2 * baseConf.getFlushInterval()); - - // restart bookies - restartBookies(); - - numMsgs += 3; - Enumeration seq = lh2.readEntries(0, numMsgs - 1); - assertTrue("Enumeration of ledger entries has no element", seq.hasMoreElements()); - int entryId = 0; - while (seq.hasMoreElements()) { - LedgerEntry e = seq.nextElement(); - assertEquals(entryId, e.getEntryId()); - - assertArrayEquals(dummyMsg.getBytes(), e.getEntry()); - ++entryId; - } - assertEquals(entryId, numMsgs); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexPersistenceMgrTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexPersistenceMgrTest.java deleted file mode 100644 index d5296c39aca..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexPersistenceMgrTest.java +++ /dev/null @@ -1,528 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.security.GeneralSecurityException; -import java.util.Arrays; -import java.util.Collections; -import org.apache.bookkeeper.bookie.FileInfoBackingCache.CachedFileInfo; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.common.util.Watcher; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.SnapshotMap; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Test cases for IndexPersistenceMgr. - */ -public class IndexPersistenceMgrTest { - - ServerConfiguration conf; - File journalDir, ledgerDir1, ledgerDir2; - LedgerDirsManager ledgerDirsManager; - LedgerDirsMonitor ledgerMonitor; - - @Before - public void setUp() throws Exception { - journalDir = File.createTempFile("IndexPersistenceMgr", "Journal"); - journalDir.delete(); - journalDir.mkdir(); - ledgerDir1 = File.createTempFile("IndexPersistenceMgr", "Ledger1"); - ledgerDir1.delete(); - ledgerDir1.mkdir(); - ledgerDir2 = File.createTempFile("IndexPersistenceMgr", "Ledger2"); - ledgerDir2.delete(); - ledgerDir2.mkdir(); - // Create current directories - BookieImpl.getCurrentDirectory(journalDir).mkdir(); - BookieImpl.getCurrentDirectory(ledgerDir1).mkdir(); - BookieImpl.getCurrentDirectory(ledgerDir2).mkdir(); - - conf = new ServerConfiguration(); - conf.setMetadataServiceUri(null); - conf.setJournalDirName(journalDir.getPath()); - conf.setLedgerDirNames(new String[] { ledgerDir1.getPath(), ledgerDir2.getPath() }); - - ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - ledgerMonitor = new LedgerDirsMonitor(conf, - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), - Collections.singletonList(ledgerDirsManager)); - ledgerMonitor.init(); - } - - @After - public void tearDown() throws Exception { - ledgerMonitor.shutdown(); - FileUtils.deleteDirectory(journalDir); - FileUtils.deleteDirectory(ledgerDir1); - FileUtils.deleteDirectory(ledgerDir2); - } - - private IndexPersistenceMgr createIndexPersistenceManager(int openFileLimit) throws Exception { - ServerConfiguration newConf = new ServerConfiguration(); - newConf.addConfiguration(conf); - newConf.setOpenFileLimit(openFileLimit); - - return new IndexPersistenceMgr( - newConf.getPageSize(), newConf.getPageSize() / LedgerEntryPage.getIndexEntrySize(), - newConf, new SnapshotMap(), ledgerDirsManager, NullStatsLogger.INSTANCE); - } - - private static void getNumFileInfos(IndexPersistenceMgr indexPersistenceMgr, - int numFiles, byte[] masterKey) throws Exception { - for (int i = 0; i < numFiles; i++) { - indexPersistenceMgr.getFileInfo((long) i, masterKey); - } - } - - @Test - public void testEvictFileInfoWhenUnderlyingFileExists() throws Exception { - evictFileInfoTest(true); - } - - @Test - public void testEvictFileInfoWhenUnderlyingFileDoesntExist() throws Exception { - evictFileInfoTest(false); - } - - private void evictFileInfoTest(boolean createFile) throws Exception { - IndexPersistenceMgr indexPersistenceMgr = createIndexPersistenceManager(2); - try { - long lid = 99999L; - byte[] masterKey = "evict-file-info".getBytes(UTF_8); - // get file info and make sure the file created - FileInfo fi = indexPersistenceMgr.getFileInfo(lid, masterKey); - if (createFile) { - fi.checkOpen(true); - } - fi.setFenced(); - - // fill up the cache to evict file infos - getNumFileInfos(indexPersistenceMgr, 10, masterKey); - - // get the file info again, state should have been flushed - fi = indexPersistenceMgr.getFileInfo(lid, masterKey); - assertTrue("Fence bit should be persisted", fi.isFenced()); - } finally { - indexPersistenceMgr.close(); - } - } - - final long lid = 1L; - final byte[] masterKey = "write".getBytes(); - - @Test - public void testGetFileInfoReadBeforeWrite() throws Exception { - IndexPersistenceMgr indexPersistenceMgr = null; - try { - indexPersistenceMgr = createIndexPersistenceManager(1); - // get the file info for read - try { - indexPersistenceMgr.getFileInfo(lid, null); - fail("Should fail get file info for reading if the file doesn't exist"); - } catch (Bookie.NoLedgerException nle) { - // exepcted - } - assertEquals(0, indexPersistenceMgr.writeFileInfoCache.size()); - assertEquals(0, indexPersistenceMgr.readFileInfoCache.size()); - - CachedFileInfo writeFileInfo = indexPersistenceMgr.getFileInfo(lid, masterKey); - assertEquals(2, writeFileInfo.getRefCount()); - assertEquals(1, indexPersistenceMgr.writeFileInfoCache.size()); - assertEquals(0, indexPersistenceMgr.readFileInfoCache.size()); - writeFileInfo.release(); - assertEquals(1, writeFileInfo.getRefCount()); - } finally { - if (null != indexPersistenceMgr) { - indexPersistenceMgr.close(); - } - } - } - - @Test - public void testGetFileInfoWriteBeforeRead() throws Exception { - IndexPersistenceMgr indexPersistenceMgr = null; - try { - indexPersistenceMgr = createIndexPersistenceManager(1); - - CachedFileInfo writeFileInfo = indexPersistenceMgr.getFileInfo(lid, masterKey); - assertEquals(2, writeFileInfo.getRefCount()); - assertEquals(1, indexPersistenceMgr.writeFileInfoCache.size()); - assertEquals(0, indexPersistenceMgr.readFileInfoCache.size()); - writeFileInfo.release(); - - CachedFileInfo readFileInfo = indexPersistenceMgr.getFileInfo(lid, null); - assertEquals(3, readFileInfo.getRefCount()); - assertEquals(1, indexPersistenceMgr.writeFileInfoCache.size()); - assertEquals(1, indexPersistenceMgr.readFileInfoCache.size()); - readFileInfo.release(); - assertEquals(2, writeFileInfo.getRefCount()); - assertEquals(2, readFileInfo.getRefCount()); - } finally { - if (null != indexPersistenceMgr) { - indexPersistenceMgr.close(); - } - } - } - - @Test - public void testReadFileInfoCacheEviction() throws Exception { - IndexPersistenceMgr indexPersistenceMgr = null; - try { - indexPersistenceMgr = createIndexPersistenceManager(1); - for (int i = 0; i < 3; i++) { - CachedFileInfo fileInfo = indexPersistenceMgr.getFileInfo(lid + i, masterKey); - // We need to make sure index file is created, otherwise the test case can be flaky - fileInfo.checkOpen(true); - fileInfo.release(); - - // load into read cache also - indexPersistenceMgr.getFileInfo(lid + i, null).release(); - } - - indexPersistenceMgr.getFileInfo(lid, masterKey); - assertEquals(1, indexPersistenceMgr.writeFileInfoCache.size()); - assertEquals(2, indexPersistenceMgr.readFileInfoCache.size()); - - // trigger file info eviction on read file info cache - for (int i = 1; i <= 2; i++) { - indexPersistenceMgr.getFileInfo(lid + i, null); - } - assertEquals(1, indexPersistenceMgr.writeFileInfoCache.size()); - assertEquals(2, indexPersistenceMgr.readFileInfoCache.size()); - - CachedFileInfo fileInfo = indexPersistenceMgr.writeFileInfoCache.asMap().get(lid); - assertNotNull(fileInfo); - assertEquals(2, fileInfo.getRefCount()); - fileInfo = indexPersistenceMgr.writeFileInfoCache.asMap().get(lid + 1); - assertNull(fileInfo); - fileInfo = indexPersistenceMgr.writeFileInfoCache.asMap().get(lid + 2); - assertNull(fileInfo); - fileInfo = indexPersistenceMgr.readFileInfoCache.asMap().get(lid); - assertNull(fileInfo); - fileInfo = indexPersistenceMgr.readFileInfoCache.asMap().get(lid + 1); - assertNotNull(fileInfo); - assertEquals(2, fileInfo.getRefCount()); - fileInfo = indexPersistenceMgr.readFileInfoCache.asMap().get(lid + 2); - assertNotNull(fileInfo); - assertEquals(2, fileInfo.getRefCount()); - } finally { - if (null != indexPersistenceMgr) { - indexPersistenceMgr.close(); - } - } - } - - @Test - public void testEvictionShouldNotAffectLongPollRead() throws Exception { - IndexPersistenceMgr indexPersistenceMgr = null; - Watcher watcher = notification -> notification.recycle(); - try { - indexPersistenceMgr = createIndexPersistenceManager(1); - indexPersistenceMgr.getFileInfo(lid, masterKey); - indexPersistenceMgr.getFileInfo(lid, null); - indexPersistenceMgr.updateLastAddConfirmed(lid, 1); - // watch should succeed because ledger is not evicted or closed - assertTrue( - indexPersistenceMgr.waitForLastAddConfirmedUpdate(lid, 1, watcher)); - // now evict ledger 1 from write cache - indexPersistenceMgr.getFileInfo(lid + 1, masterKey); - // even if ledger 1 is evicted from write cache, watcher should still succeed - assertTrue( - indexPersistenceMgr.waitForLastAddConfirmedUpdate(lid, 1, watcher)); - // now evict ledger 1 from read cache - indexPersistenceMgr.getFileInfo(lid + 2, masterKey); - indexPersistenceMgr.getFileInfo(lid + 2, null); - // even if ledger 1 is evicted from both cache, watcher should still succeed because it - // will create a new FileInfo when cache miss - assertTrue( - indexPersistenceMgr.waitForLastAddConfirmedUpdate(lid, 1, watcher)); - } finally { - if (null != indexPersistenceMgr) { - indexPersistenceMgr.close(); - } - } - } - - @Test - public void testEvictBeforeReleaseRace() throws Exception { - IndexPersistenceMgr indexPersistenceMgr = null; - Watcher watcher = notification -> notification.recycle(); - try { - indexPersistenceMgr = createIndexPersistenceManager(1); - - indexPersistenceMgr.getFileInfo(1L, masterKey); - indexPersistenceMgr.getFileInfo(2L, masterKey); - indexPersistenceMgr.getFileInfo(3L, masterKey); - indexPersistenceMgr.getFileInfo(4L, masterKey); - - CachedFileInfo fi = indexPersistenceMgr.getFileInfo(1L, masterKey); - - // trigger eviction - indexPersistenceMgr.getFileInfo(2L, masterKey); - indexPersistenceMgr.getFileInfo(3L, null); - indexPersistenceMgr.getFileInfo(4L, null); - - Thread.sleep(1000); - - fi.setFenced(); - fi.release(); - - assertTrue(indexPersistenceMgr.isFenced(1)); - } finally { - if (null != indexPersistenceMgr) { - indexPersistenceMgr.close(); - } - } - } - - /* - * In this testcase index files (FileInfos) are precreated with different - * FileInfo header versions (FileInfo.V0 and FileInfo.V1) and it is - * validated that the current implementation of IndexPersistenceMgr (and - * corresponding FileInfo) is able to function as per the specifications of - * FileInfo header version. If it is FileInfo.V0 then explicitLac is not - * persisted and if it is FileInfo.V1 then explicitLac is persisted. - */ - @Test - public void testFileInfosOfVariousHeaderVersions() throws Exception { - IndexPersistenceMgr indexPersistenceMgr = null; - try { - indexPersistenceMgr = createIndexPersistenceManager(1); - long ledgerIdWithVersionZero = 25L; - validateFileInfo(indexPersistenceMgr, ledgerIdWithVersionZero, FileInfo.V0); - - long ledgerIdWithVersionOne = 135L; - validateFileInfo(indexPersistenceMgr, ledgerIdWithVersionOne, FileInfo.V1); - } finally { - if (null != indexPersistenceMgr) { - indexPersistenceMgr.close(); - } - } - } - - @Test - public void testIndexFileRelocation() throws Exception { - final long ledgerId = Integer.MAX_VALUE; - final String ledgerName = IndexPersistenceMgr.getLedgerName(ledgerId); - - IndexPersistenceMgr indexPersistenceMgr = createIndexPersistenceManager(1); - preCreateFileInfoForLedgerInDir1(ledgerId, FileInfo.V1); - - ledgerDirsManager.addToFilledDirs(BookieImpl.getCurrentDirectory(ledgerDir1)); - indexPersistenceMgr.flushLedgerHeader(ledgerId); - - File expectedIndexFile = new File(BookieImpl.getCurrentDirectory(ledgerDir2), ledgerName); - CachedFileInfo fileInfo = indexPersistenceMgr.getFileInfo(ledgerId, null); - assertTrue(fileInfo.isSameFile(expectedIndexFile)); - assertFalse(fileInfo.isDeleted()); - - indexPersistenceMgr.close(); - - // Test startup after clean shutdown. - // - // Index file should stay in original location. - IndexPersistenceMgr indexPersistenceMgr2 = createIndexPersistenceManager(1); - CachedFileInfo fileInfo2 = indexPersistenceMgr2.getFileInfo(ledgerId, null); - assertTrue(fileInfo2.isSameFile(expectedIndexFile)); - indexPersistenceMgr2.close(); - } - - @Test - public void testIndexFileRelocationCrashBeforeOriginalFileDeleted() throws Exception { - final long ledgerId = Integer.MAX_VALUE; - final String ledgerName = IndexPersistenceMgr.getLedgerName(ledgerId); - final String reason = "crash before original file deleted"; - - try { - IndexPersistenceMgr indexPersistenceMgr = createIndexPersistenceManager(1); - preCreateFileInfoForLedgerInDir1(ledgerId, FileInfo.V1); - - CachedFileInfo fileInfo = spy(indexPersistenceMgr.getFileInfo(ledgerId, null)); - doAnswer(invocation -> { - throw new RuntimeException(reason); - }).when(fileInfo).delete(); - indexPersistenceMgr.readFileInfoCache.put(ledgerId, fileInfo); - - ledgerDirsManager.addToFilledDirs(BookieImpl.getCurrentDirectory(ledgerDir1)); - indexPersistenceMgr.flushLedgerHeader(ledgerId); - fail("should fail due to " + reason); - } catch (RuntimeException ex) { - assertEquals(reason, ex.getMessage()); - } - - // Test startup after: - // 1. relocation file created. - // 2. crashed with possible corrupted relocation file. - // - // Index file should stay in original location in this case. - IndexPersistenceMgr indexPersistenceMgr2 = createIndexPersistenceManager(1); - File expectedIndexFile = new File(BookieImpl.getCurrentDirectory(ledgerDir1), ledgerName); - CachedFileInfo fileInfo2 = indexPersistenceMgr2.getFileInfo(ledgerId, null); - assertTrue(fileInfo2.isSameFile(expectedIndexFile)); - indexPersistenceMgr2.close(); - } - - @Test - public void testIndexFileRelocationCrashAfterOriginalFileDeleted() throws Exception { - final long ledgerId = Integer.MAX_VALUE; - final String ledgerName = IndexPersistenceMgr.getLedgerName(ledgerId); - final String reason = "crash after original file deleted"; - - try { - IndexPersistenceMgr indexPersistenceMgr = createIndexPersistenceManager(1); - preCreateFileInfoForLedgerInDir1(ledgerId, FileInfo.V1); - - CachedFileInfo fileInfo = spy(indexPersistenceMgr.getFileInfo(ledgerId, null)); - doAnswer(invocation -> { - invocation.callRealMethod(); - throw new RuntimeException(reason); - }).when(fileInfo).delete(); - indexPersistenceMgr.readFileInfoCache.put(ledgerId, fileInfo); - - ledgerDirsManager.addToFilledDirs(BookieImpl.getCurrentDirectory(ledgerDir1)); - indexPersistenceMgr.flushLedgerHeader(ledgerId); - fail("should fail due to " + reason); - } catch (RuntimeException ex) { - assertEquals(reason, ex.getMessage()); - } - - // Test startup after: - // 1. relocation file created, filled and synced. - // 2. original index file deleted. - // 3. crashed. - // - // Index file should stay in new location in this case. - IndexPersistenceMgr indexPersistenceMgr2 = createIndexPersistenceManager(1); - File expectedIndexFile = new File(BookieImpl.getCurrentDirectory(ledgerDir2), ledgerName); - CachedFileInfo fileInfo2 = indexPersistenceMgr2.getFileInfo(ledgerId, null); - assertTrue(fileInfo2.isSameFile(expectedIndexFile)); - indexPersistenceMgr2.close(); - } - - void validateFileInfo(IndexPersistenceMgr indexPersistenceMgr, long ledgerId, int headerVersion) - throws IOException, GeneralSecurityException { - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - boolean getUseV2WireProtocol = true; - - preCreateFileInfoForLedgerInDir1(ledgerId, headerVersion); - DigestManager digestManager = DigestManager.instantiate(ledgerId, masterKey, - BookKeeper.DigestType.toProtoDigestType(digestType), UnpooledByteBufAllocator.DEFAULT, - getUseV2WireProtocol); - - CachedFileInfo fileInfo = indexPersistenceMgr.getFileInfo(ledgerId, masterKey); - fileInfo.readHeader(); - assertEquals("ExplicitLac should be null", null, fileInfo.getExplicitLac()); - assertEquals("Header Version should match with precreated fileinfos headerversion", headerVersion, - fileInfo.headerVersion); - assertTrue("Masterkey should match with precreated fileinfos masterkey", - Arrays.equals(masterKey, fileInfo.masterKey)); - long explicitLac = 22; - ByteBuf explicitLacByteBuf = digestManager.computeDigestAndPackageForSendingLac(explicitLac).getBuffer(0); - explicitLacByteBuf.markReaderIndex(); - indexPersistenceMgr.setExplicitLac(ledgerId, explicitLacByteBuf); - explicitLacByteBuf.resetReaderIndex(); - assertEquals("explicitLac ByteBuf contents should match", 0, - ByteBufUtil.compare(explicitLacByteBuf, indexPersistenceMgr.getExplicitLac(ledgerId))); - /* - * release fileInfo untill it is marked dead and closed, so that - * contents of it are persisted. - */ - while (fileInfo.refCount.get() != FileInfoBackingCache.DEAD_REF) { - fileInfo.release(); - } - /* - * reopen the fileinfo and readHeader, so that whatever was persisted - * would be read. - */ - fileInfo = indexPersistenceMgr.getFileInfo(ledgerId, masterKey); - fileInfo.readHeader(); - assertEquals("Header Version should match with precreated fileinfos headerversion even after reopening", - headerVersion, fileInfo.headerVersion); - assertTrue("Masterkey should match with precreated fileinfos masterkey", - Arrays.equals(masterKey, fileInfo.masterKey)); - if (headerVersion == FileInfo.V0) { - assertEquals("Since it is V0 Header, explicitLac will not be persisted and should be null after reopening", - null, indexPersistenceMgr.getExplicitLac(ledgerId)); - } else { - explicitLacByteBuf.resetReaderIndex(); - assertEquals("Since it is V1 Header, explicitLac will be persisted and should not be null after reopening", - 0, ByteBufUtil.compare(explicitLacByteBuf, indexPersistenceMgr.getExplicitLac(ledgerId))); - } - } - - void preCreateFileInfoForLedgerInDir1(long ledgerId, int headerVersion) throws IOException { - File ledgerCurDir = BookieImpl.getCurrentDirectory(ledgerDir1); - String ledgerName = IndexPersistenceMgr.getLedgerName(ledgerId); - File indexFile = new File(ledgerCurDir, ledgerName); - indexFile.getParentFile().mkdirs(); - indexFile.createNewFile(); - /* - * precreate index file (FileInfo) for the ledger with specified - * headerversion. Even in FileInfo.V1 case, it is valid for - * explicitLacBufLength to be 0. If it is 0, then explicitLac is - * considered null (not set). - */ - try (RandomAccessFile raf = new RandomAccessFile(indexFile, "rw")) { - FileChannel fcForIndexFile = raf.getChannel(); - ByteBuffer bb = ByteBuffer.allocate((int) FileInfo.START_OF_DATA); - bb.putInt(FileInfo.SIGNATURE); - bb.putInt(headerVersion); - bb.putInt(masterKey.length); - bb.put(masterKey); - // statebits - bb.putInt(0); - if (headerVersion == FileInfo.V1) { - // explicitLacBufLength - bb.putInt(0); - } - bb.rewind(); - fcForIndexFile.position(0); - fcForIndexFile.write(bb); - fcForIndexFile.close(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorageTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorageTest.java deleted file mode 100644 index ce514632033..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorageTest.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.BOOKIE_SCOPE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.STORAGE_SCRUB_PAGE_RETRIES; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.PrimitiveIterator.OfLong; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.Semaphore; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.IntStream; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.EntryFormatter; -import org.apache.bookkeeper.util.LedgerIdFormatter; -import org.apache.commons.lang.mutable.MutableInt; -import org.apache.commons.lang.mutable.MutableLong; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test for InterleavedLedgerStorage. - */ -@RunWith(Parameterized.class) -public class InterleavedLedgerStorageTest { - private static final Logger LOG = LoggerFactory.getLogger(InterleavedLedgerStorageTest.class); - - @Parameterized.Parameters - public static Iterable elplSetting() { - return Arrays.asList(true, false); - } - - public InterleavedLedgerStorageTest(boolean elplSetting) { - conf.setEntryLogSizeLimit(2048); - conf.setEntryLogPerLedgerEnabled(elplSetting); - } - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - static class TestableDefaultEntryLogger extends DefaultEntryLogger { - public interface CheckEntryListener { - void accept(long ledgerId, - long entryId, - long entryLogId, - long pos); - } - volatile CheckEntryListener testPoint; - - public TestableDefaultEntryLogger( - ServerConfiguration conf, - LedgerDirsManager ledgerDirsManager, - EntryLogListener listener, - StatsLogger statsLogger) throws IOException { - super(conf, ledgerDirsManager, listener, statsLogger, UnpooledByteBufAllocator.DEFAULT); - } - - void setCheckEntryTestPoint(CheckEntryListener testPoint) throws InterruptedException { - this.testPoint = testPoint; - } - - @Override - void checkEntry(long ledgerId, long entryId, long location) throws EntryLookupException, IOException { - CheckEntryListener runBefore = testPoint; - if (runBefore != null) { - runBefore.accept(ledgerId, entryId, logIdForOffset(location), posForOffset(location)); - } - super.checkEntry(ledgerId, entryId, location); - } - } - - TestStatsProvider statsProvider = new TestStatsProvider(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - LedgerDirsManager ledgerDirsManager; - TestableDefaultEntryLogger entryLogger; - InterleavedLedgerStorage interleavedStorage = new InterleavedLedgerStorage(); - final long numWrites = 2000; - final long moreNumOfWrites = 3000; - final long entriesPerWrite = 2; - final long numOfLedgers = 5; - - @Before - public void setUp() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - conf.setLedgerDirNames(new String[]{tmpDir.toString()}); - ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - entryLogger = new TestableDefaultEntryLogger( - conf, ledgerDirsManager, null, NullStatsLogger.INSTANCE); - interleavedStorage.initializeWithEntryLogger( - conf, null, ledgerDirsManager, ledgerDirsManager, - entryLogger, statsProvider.getStatsLogger(BOOKIE_SCOPE)); - interleavedStorage.setCheckpointer(checkpointer); - interleavedStorage.setCheckpointSource(checkpointSource); - - // Insert some ledger & entries in the interleaved storage - for (long entryId = 0; entryId < numWrites; entryId++) { - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - if (entryId == 0) { - interleavedStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - interleavedStorage.setFenced(ledgerId); - } - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId * entriesPerWrite); - entry.writeBytes(("entry-" + entryId).getBytes()); - - interleavedStorage.addEntry(entry); - } - } - } - - @Test - public void testIndexEntryIterator() throws Exception { - try (LedgerCache.PageEntriesIterable pages = interleavedStorage.getIndexEntries(0)) { - MutableLong curEntry = new MutableLong(0); - for (LedgerCache.PageEntries page : pages) { - try (LedgerEntryPage lep = page.getLEP()) { - lep.getEntries((entry, offset) -> { - Assert.assertEquals(curEntry.longValue(), entry); - Assert.assertNotEquals(0, offset); - curEntry.setValue(entriesPerWrite + entry); - return true; - }); - } - } - Assert.assertEquals(entriesPerWrite * numWrites, curEntry.longValue()); - } - } - - @Test - public void testGetListOfEntriesOfLedger() throws IOException { - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - OfLong entriesOfLedger = interleavedStorage.getListOfEntriesOfLedger(ledgerId); - ArrayList arrayList = new ArrayList(); - Consumer addMethod = arrayList::add; - entriesOfLedger.forEachRemaining(addMethod); - assertEquals("Number of entries", numWrites, arrayList.size()); - assertTrue("Entries of Ledger", IntStream.range(0, arrayList.size()).allMatch(i -> { - return arrayList.get(i) == (i * entriesPerWrite); - })); - } - - long nonExistingLedger = 456789L; - OfLong entriesOfLedger = interleavedStorage.getListOfEntriesOfLedger(nonExistingLedger); - assertFalse("There shouldn't be any entry", entriesOfLedger.hasNext()); - } - - @Test - public void testGetListOfEntriesOfLedgerAfterFlush() throws IOException { - interleavedStorage.flush(); - - // Insert some more ledger & entries in the interleaved storage - for (long entryId = numWrites; entryId < moreNumOfWrites; entryId++) { - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId * entriesPerWrite); - entry.writeBytes(("entry-" + entryId).getBytes()); - - interleavedStorage.addEntry(entry); - } - } - - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - OfLong entriesOfLedger = interleavedStorage.getListOfEntriesOfLedger(ledgerId); - ArrayList arrayList = new ArrayList(); - Consumer addMethod = arrayList::add; - entriesOfLedger.forEachRemaining(addMethod); - assertEquals("Number of entries", moreNumOfWrites, arrayList.size()); - assertTrue("Entries of Ledger", IntStream.range(0, arrayList.size()).allMatch(i -> { - return arrayList.get(i) == (i * entriesPerWrite); - })); - } - } - - @Test - public void testConsistencyCheckConcurrentGC() throws Exception { - final long signalDone = -1; - final List asyncErrors = new ArrayList<>(); - final LinkedBlockingQueue toCompact = new LinkedBlockingQueue<>(); - final Semaphore awaitingCompaction = new Semaphore(0); - - interleavedStorage.flush(); - final long lastLogId = entryLogger.getLeastUnflushedLogId(); - - final MutableInt counter = new MutableInt(0); - entryLogger.setCheckEntryTestPoint((ledgerId, entryId, entryLogId, pos) -> { - if (entryLogId < lastLogId) { - if (counter.intValue() % 100 == 0) { - try { - toCompact.put(entryLogId); - awaitingCompaction.acquire(); - } catch (InterruptedException e) { - asyncErrors.add(e); - } - } - counter.increment(); - } - }); - - Thread mutator = new Thread(() -> { - EntryLogCompactor compactor = new EntryLogCompactor( - conf, - entryLogger, - interleavedStorage, - entryLogger::removeEntryLog); - while (true) { - Long next = null; - try { - next = toCompact.take(); - if (next == null || next == signalDone) { - break; - } - compactor.compact(entryLogger.getEntryLogMetadata(next)); - } catch (BufferedChannelBase.BufferedChannelClosedException e) { - // next was already removed, ignore - } catch (Exception e) { - asyncErrors.add(e); - break; - } finally { - if (next != null) { - awaitingCompaction.release(); - } - } - } - }); - mutator.start(); - - List inconsistencies = interleavedStorage.localConsistencyCheck( - Optional.empty()); - for (LedgerStorage.DetectedInconsistency e: inconsistencies) { - LOG.error("Found: {}", e); - } - Assert.assertEquals(0, inconsistencies.size()); - - toCompact.offer(signalDone); - mutator.join(); - for (Exception e: asyncErrors) { - throw e; - } - - if (!conf.isEntryLogPerLedgerEnabled()) { - Assert.assertNotEquals( - 0, - statsProvider.getCounter(BOOKIE_SCOPE + "." + STORAGE_SCRUB_PAGE_RETRIES).get().longValue()); - } - } - - @Test - public void testConsistencyMissingEntry() throws Exception { - // set 1, 1 to nonsense - interleavedStorage.ledgerCache.putEntryOffset(1, 1, 0xFFFFFFFFFFFFFFFFL); - - List errors = interleavedStorage.localConsistencyCheck(Optional.empty()); - Assert.assertEquals(1, errors.size()); - LedgerStorage.DetectedInconsistency inconsistency = errors.remove(0); - Assert.assertEquals(1, inconsistency.getEntryId()); - Assert.assertEquals(1, inconsistency.getLedgerId()); - } - - @Test - public void testWrongEntry() throws Exception { - // set 1, 1 to nonsense - interleavedStorage.ledgerCache.putEntryOffset( - 1, - 1, - interleavedStorage.ledgerCache.getEntryOffset(0, 0)); - - List errors = interleavedStorage.localConsistencyCheck(Optional.empty()); - Assert.assertEquals(1, errors.size()); - LedgerStorage.DetectedInconsistency inconsistency = errors.remove(0); - Assert.assertEquals(1, inconsistency.getEntryId()); - Assert.assertEquals(1, inconsistency.getLedgerId()); - } - - @Test - public void testShellCommands() throws Exception { - interleavedStorage.flush(); - interleavedStorage.shutdown(); - final Pattern entryPattern = Pattern.compile( - "entry (?\\d+)\t:\t((?N/A)|\\(log:(?\\d+), pos: (?\\d+)\\))"); - - class Metadata { - final Pattern keyPattern = Pattern.compile("master key +: ([0-9a-f])"); - final Pattern sizePattern = Pattern.compile("size +: (\\d+)"); - final Pattern entriesPattern = Pattern.compile("entries +: (\\d+)"); - final Pattern isFencedPattern = Pattern.compile("isFenced +: (\\w+)"); - - public String masterKey; - public long size = -1; - public long entries = -1; - public boolean foundFenced = false; - - void check(String s) { - Matcher keyMatcher = keyPattern.matcher(s); - if (keyMatcher.matches()) { - masterKey = keyMatcher.group(1); - return; - } - - Matcher sizeMatcher = sizePattern.matcher(s); - if (sizeMatcher.matches()) { - size = Long.parseLong(sizeMatcher.group(1)); - return; - } - - Matcher entriesMatcher = entriesPattern.matcher(s); - if (entriesMatcher.matches()) { - entries = Long.parseLong(entriesMatcher.group(1)); - return; - } - - Matcher isFencedMatcher = isFencedPattern.matcher(s); - if (isFencedMatcher.matches()) { - Assert.assertEquals("true", isFencedMatcher.group(1)); - foundFenced = true; - return; - } - } - - void validate(long foundEntries) { - Assert.assertTrue(entries >= numWrites * entriesPerWrite); - Assert.assertEquals(entries, foundEntries); - Assert.assertTrue(foundFenced); - Assert.assertNotEquals(-1, size); - } - } - final Metadata foundMetadata = new Metadata(); - - AtomicLong curEntry = new AtomicLong(0); - AtomicLong someEntryLogger = new AtomicLong(-1); - BookieShell shell = new BookieShell( - LedgerIdFormatter.LONG_LEDGERID_FORMATTER, EntryFormatter.STRING_FORMATTER) { - @Override - void printInfoLine(String s) { - Matcher matcher = entryPattern.matcher(s); - System.out.println(s); - if (matcher.matches()) { - assertEquals(Long.toString(curEntry.get()), matcher.group("entry")); - - if (matcher.group("na") == null) { - String logId = matcher.group("logid"); - Assert.assertNotEquals(matcher.group("logid"), null); - Assert.assertNotEquals(matcher.group("pos"), null); - Assert.assertTrue((curEntry.get() % entriesPerWrite) == 0); - Assert.assertTrue(curEntry.get() <= numWrites * entriesPerWrite); - if (someEntryLogger.get() == -1) { - someEntryLogger.set(Long.parseLong(logId)); - } - } else { - Assert.assertEquals(matcher.group("logid"), null); - Assert.assertEquals(matcher.group("pos"), null); - Assert.assertTrue(((curEntry.get() % entriesPerWrite) != 0) - || ((curEntry.get() >= (entriesPerWrite * numWrites)))); - } - curEntry.incrementAndGet(); - } else { - foundMetadata.check(s); - } - } - }; - shell.setConf(conf); - int res = shell.run(new String[] { "ledger", "-m", "0" }); - Assert.assertEquals(0, res); - Assert.assertTrue(curEntry.get() >= numWrites * entriesPerWrite); - foundMetadata.validate(curEntry.get()); - - // Should pass consistency checker - res = shell.run(new String[] { "localconsistencycheck" }); - Assert.assertEquals(0, res); - - - // Remove a logger - DefaultEntryLogger entryLogger = new DefaultEntryLogger(conf); - entryLogger.removeEntryLog(someEntryLogger.get()); - - // Should fail consistency checker - res = shell.run(new String[] { "localconsistencycheck" }); - Assert.assertEquals(1, res); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LastAddConfirmedUpdateNotificationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LastAddConfirmedUpdateNotificationTest.java deleted file mode 100644 index 90da463b664..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LastAddConfirmedUpdateNotificationTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test of {@link LastAddConfirmedUpdateNotification}. - */ -public class LastAddConfirmedUpdateNotificationTest { - - @Test - public void testGetters() { - long lac = System.currentTimeMillis(); - LastAddConfirmedUpdateNotification notification = LastAddConfirmedUpdateNotification.of(lac); - - long timestamp = System.currentTimeMillis(); - assertEquals(lac, notification.getLastAddConfirmed()); - assertTrue(notification.getTimestamp() <= timestamp); - - notification.recycle(); - } - - @Test - public void testRecycle() { - long lac = System.currentTimeMillis(); - LastAddConfirmedUpdateNotification notification = LastAddConfirmedUpdateNotification.of(lac); - notification.recycle(); - - assertEquals(-1L, notification.getLastAddConfirmed()); - assertEquals(-1L, notification.getTimestamp()); - } - - @Test - public void testFunc() { - long lac = System.currentTimeMillis(); - LastAddConfirmedUpdateNotification notification = LastAddConfirmedUpdateNotification.FUNC.apply(lac); - - assertEquals(lac, notification.getLastAddConfirmed()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerCacheTest.java deleted file mode 100644 index 4e8f06fe7f4..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerCacheTest.java +++ /dev/null @@ -1,926 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.BookieException.Code.OK; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.bookie.Bookie.NoLedgerException; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.FileInfoBackingCache.CachedFileInfo; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.bookkeeper.util.SnapshotMap; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * LedgerCache related test cases. - */ -public class LedgerCacheTest { - private static final Logger LOG = LoggerFactory.getLogger(LedgerCacheTest.class); - - SnapshotMap activeLedgers; - LedgerCache ledgerCache; - Thread flushThread; - ServerConfiguration conf; - File txnDir, ledgerDir; - - private final List tempDirs = new ArrayList(); - - private BookieImpl bookie; - - @Before - public void setUp() throws Exception { - txnDir = IOUtils.createTempDir("ledgercache", "txn"); - ledgerDir = IOUtils.createTempDir("ledgercache", "ledger"); - // create current dir - new File(ledgerDir, BookKeeperConstants.CURRENT_DIR).mkdir(); - - conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(null); - conf.setJournalDirName(txnDir.getPath()); - conf.setLedgerDirNames(new String[] { ledgerDir.getPath() }); - bookie = new TestBookieImpl(conf); - - activeLedgers = new SnapshotMap(); - ledgerCache = ((InterleavedLedgerStorage) bookie.getLedgerStorage().getUnderlyingLedgerStorage()).ledgerCache; - } - - @After - public void tearDown() throws Exception { - if (flushThread != null) { - flushThread.interrupt(); - flushThread.join(); - } - bookie.getLedgerStorage().shutdown(); - FileUtils.deleteDirectory(txnDir); - FileUtils.deleteDirectory(ledgerDir); - for (File dir : tempDirs) { - FileUtils.deleteDirectory(dir); - } - } - - File createTempDir(String prefix, String suffix) throws IOException { - File dir = IOUtils.createTempDir(prefix, suffix); - tempDirs.add(dir); - return dir; - } - - private void newLedgerCache() throws IOException { - if (ledgerCache != null) { - ledgerCache.close(); - } - ledgerCache = ((InterleavedLedgerStorage) bookie.getLedgerStorage().getUnderlyingLedgerStorage()) - .ledgerCache = new LedgerCacheImpl(conf, activeLedgers, bookie.getIndexDirsManager()); - flushThread = new Thread() { - public void run() { - while (true) { - try { - sleep(conf.getFlushInterval()); - ledgerCache.flushLedger(true); - } catch (InterruptedException ie) { - // killed by teardown - Thread.currentThread().interrupt(); - return; - } catch (Exception e) { - LOG.error("Exception in flush thread", e); - } - } - } - }; - flushThread.start(); - } - - @Test - public void testAddEntryException() throws IOException { - // set page limitation - conf.setPageLimit(10); - // create a ledger cache - newLedgerCache(); - /* - * Populate ledger cache. - */ - try { - byte[] masterKey = "blah".getBytes(); - for (int i = 0; i < 100; i++) { - ledgerCache.setMasterKey((long) i, masterKey); - ledgerCache.putEntryOffset(i, 0, i * 8); - } - } catch (IOException e) { - LOG.error("Got IOException.", e); - fail("Failed to add entry."); - } - } - - @Test - public void testLedgerEviction() throws Exception { - int numEntries = 10; - // limit open files & pages - conf.setOpenFileLimit(1).setPageLimit(2) - .setPageSize(8 * numEntries); - // create ledger cache - newLedgerCache(); - try { - int numLedgers = 3; - byte[] masterKey = "blah".getBytes(); - for (int i = 1; i <= numLedgers; i++) { - ledgerCache.setMasterKey((long) i, masterKey); - for (int j = 0; j < numEntries; j++) { - ledgerCache.putEntryOffset(i, j, i * numEntries + j); - } - } - } catch (Exception e) { - LOG.error("Got Exception.", e); - fail("Failed to add entry."); - } - } - - @Test - public void testDeleteLedger() throws Exception { - int numEntries = 10; - // limit open files & pages - conf.setOpenFileLimit(999).setPageLimit(2) - .setPageSize(8 * numEntries); - // create ledger cache - newLedgerCache(); - try { - int numLedgers = 2; - byte[] masterKey = "blah".getBytes(); - for (int i = 1; i <= numLedgers; i++) { - ledgerCache.setMasterKey((long) i, masterKey); - for (int j = 0; j < numEntries; j++) { - ledgerCache.putEntryOffset(i, j, i * numEntries + j); - } - } - // ledger cache is exhausted - // delete ledgers - for (int i = 1; i <= numLedgers; i++) { - ledgerCache.deleteLedger((long) i); - } - // create num ledgers to add entries - for (int i = numLedgers + 1; i <= 2 * numLedgers; i++) { - ledgerCache.setMasterKey((long) i, masterKey); - for (int j = 0; j < numEntries; j++) { - ledgerCache.putEntryOffset(i, j, i * numEntries + j); - } - } - } catch (Exception e) { - LOG.error("Got Exception.", e); - fail("Failed to add entry."); - } - } - - @Test - public void testPageEviction() throws Exception { - int numLedgers = 10; - byte[] masterKey = "blah".getBytes(); - // limit page count - conf.setOpenFileLimit(999999).setPageLimit(3); - // create ledger cache - newLedgerCache(); - try { - // create serveral ledgers - for (int i = 1; i <= numLedgers; i++) { - ledgerCache.setMasterKey((long) i, masterKey); - ledgerCache.putEntryOffset(i, 0, i * 8); - ledgerCache.putEntryOffset(i, 1, i * 8); - } - - // flush all first to clean previous dirty ledgers - ledgerCache.flushLedger(true); - // flush all - ledgerCache.flushLedger(true); - - // delete serveral ledgers - for (int i = 1; i <= numLedgers / 2; i++) { - ledgerCache.deleteLedger(i); - } - - // bookie restarts - newLedgerCache(); - - // simulate replaying journals to add entries again - for (int i = 1; i <= numLedgers; i++) { - try { - ledgerCache.putEntryOffset(i, 1, i * 8); - } catch (NoLedgerException nsle) { - if (i <= numLedgers / 2) { - // it is ok - } else { - LOG.error("Error put entry offset : ", nsle); - fail("Should not reach here."); - } - } - } - } catch (Exception e) { - LOG.error("Got Exception.", e); - fail("Failed to add entry."); - } - } - - /** - * Test Ledger Cache flush failure. - */ - @Test - public void testLedgerCacheFlushFailureOnDiskFull() throws Exception { - File ledgerDir1 = createTempDir("bkTest", ".dir"); - File ledgerDir2 = createTempDir("bkTest", ".dir"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { ledgerDir1.getAbsolutePath(), ledgerDir2.getAbsolutePath() }); - - BookieImpl bookie = new TestBookieImpl(conf); - InterleavedLedgerStorage ledgerStorage = - ((InterleavedLedgerStorage) bookie.getLedgerStorage().getUnderlyingLedgerStorage()); - LedgerCacheImpl ledgerCache = (LedgerCacheImpl) ledgerStorage.ledgerCache; - // Create ledger index file - ledgerStorage.setMasterKey(1, "key".getBytes()); - - CachedFileInfo fileInfo = ledgerCache.getIndexPersistenceManager().getFileInfo(1L, null); - - // Add entries - ledgerStorage.addEntry(generateEntry(1, 1)); - ledgerStorage.addEntry(generateEntry(1, 2)); - ledgerStorage.flush(); - - ledgerStorage.addEntry(generateEntry(1, 3)); - // add the dir to failed dirs - bookie.getIndexDirsManager().addToFilledDirs( - fileInfo.getLf().getParentFile().getParentFile().getParentFile()); - File before = fileInfo.getLf(); - // flush after disk is added as failed. - ledgerStorage.flush(); - File after = fileInfo.getLf(); - - assertFalse("After flush index file should be changed", before.equals(after)); - // Verify written entries - Assert.assertEquals(generateEntry(1, 1), ledgerStorage.getEntry(1, 1)); - Assert.assertEquals(generateEntry(1, 2), ledgerStorage.getEntry(1, 2)); - Assert.assertEquals(generateEntry(1, 3), ledgerStorage.getEntry(1, 3)); - } - - /** - * Test that if we are writing to more ledgers than there - * are pages, then we will not flush the index before the - * entries in the entrylogger have been persisted to disk. - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-447} - */ - @Test - public void testIndexPageEvictionWriteOrder() throws Exception { - final int numLedgers = 10; - File journalDir = createTempDir("bookie", "journal"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(journalDir)); - - File ledgerDir = createTempDir("bookie", "ledger"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(ledgerDir)); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(null); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setFlushInterval(1000) - .setPageLimit(1) - .setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - - Bookie b = new TestBookieImpl(conf); - b.start(); - for (int i = 1; i <= numLedgers; i++) { - ByteBuf packet = generateEntry(i, 1); - b.addEntry(packet, false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - } - - conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(null); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }); - - b = new TestBookieImpl(conf); - for (int i = 1; i <= numLedgers; i++) { - try { - b.readEntry(i, 1); - } catch (Bookie.NoLedgerException nle) { - // this is fine, means the ledger was never written to the index cache - assertEquals("No ledger should only happen for the last ledger", - i, numLedgers); - } catch (Bookie.NoEntryException nee) { - // this is fine, means the ledger was written to the index cache, but not - // the entry log - } catch (IOException ioe) { - if (ioe.getCause() instanceof DefaultEntryLogger.EntryLookupException) { - // this is fine, means the ledger was not fully written to - // the entry log - } else { - LOG.info("Shouldn't have received IOException for entry {}", i, ioe); - fail("Shouldn't throw IOException, should say that entry is not found"); - } - } - } - } - - - /** - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-524} - * Checks that getLedgerEntryPage does not throw an NPE in the - * case getFromTable returns a null ledger entry page reference. - * This NPE might kill the sync thread leaving a bookie with no - * sync thread running. - * - * @throws IOException - */ - @Test - public void testSyncThreadNPE() throws IOException { - newLedgerCache(); - try { - ((LedgerCacheImpl) ledgerCache).getIndexPageManager().getLedgerEntryPageFromCache(0L, 0L, true); - } catch (Exception e) { - LOG.error("Exception when trying to get a ledger entry page", e); - fail("Shouldn't have thrown an exception"); - } - } - - - /** - * Test for race between putEntryOffset and flush. - * {@link https://github.com/apache/bookkeeper/issues/1919} - */ - @Test - public void testPutEntryOffsetDeleteRace() throws Exception { - newLedgerCache(); - final AtomicInteger rc = new AtomicInteger(0); - final LinkedBlockingQueue putQ = new LinkedBlockingQueue<>(100); - final LinkedBlockingQueue deleteQ = new LinkedBlockingQueue<>(100); - final byte[] masterKey = "masterKey".getBytes(); - final long numLedgers = 1000; - final int numPutters = 10; - final int numDeleters = 10; - final AtomicBoolean running = new AtomicBoolean(true); - Thread newLedgerThread = new Thread() { - public void run() { - try { - for (long i = 0; i < numLedgers && rc.get() == 0; i++) { - ledgerCache.setMasterKey(i, masterKey); - - ledgerCache.putEntryOffset(i, 1, 0); - deleteQ.put(i); - putQ.put(i); - } - for (int i = 0; i < numPutters; ++i) { - putQ.put(-1L); - } - for (int i = 0; i < numDeleters; ++i) { - deleteQ.put(-1L); - } - } catch (Throwable e) { - rc.set(-1); - LOG.error("Exception in new ledger thread", e); - } - } - }; - newLedgerThread.start(); - - Thread[] flushThreads = new Thread[numPutters]; - for (int i = 0; i < numPutters; ++i) { - Thread flushThread = new Thread() { - public void run() { - try { - while (true) { - long id = putQ.take(); - if (id == -1L) { - break; - } - LOG.info("Putting {}", id); - try { - ledgerCache.putEntryOffset(id, 2, 0); - ledgerCache.deleteLedger(id); - } catch (NoLedgerException e) { - // No problem - } - } - } catch (Throwable e) { - rc.set(-1); - LOG.error("Exception in put thread", e); - } - } - }; - flushThread.start(); - flushThreads[i] = flushThread; - } - - Thread[] deleteThreads = new Thread[numDeleters]; - for (int i = 0; i < numDeleters; ++i) { - Thread deleteThread = new Thread() { - public void run() { - try { - while (true) { - long id = deleteQ.take(); - if (id == -1L) { - break; - } - LOG.info("Deleting {}", id); - try { - ledgerCache.deleteLedger(id); - } catch (NoLedgerException e) { - // No problem - } - } - } catch (Throwable e) { - rc.set(-1); - LOG.error("Exception in delete thread", e); - } - } - }; - deleteThread.start(); - deleteThreads[i] = deleteThread; - } - - newLedgerThread.join(); - - for (Thread deleteThread : deleteThreads) { - deleteThread.join(); - } - - running.set(false); - for (Thread flushThread : flushThreads) { - flushThread.join(); - } - - assertEquals("Should have been no errors", rc.get(), 0); - for (long i = 0L; i < numLedgers; ++i) { - boolean gotError = false; - try { - LOG.error("Checking {}", i); - ledgerCache.getEntryOffset(i, 0); - } catch (NoLedgerException e) { - gotError = true; - } - if (!gotError) { - LOG.error("Ledger {} is still around", i); - fail("Found ledger " + i + ", which should have been removed"); - } - } - } - - /** - * Test for race between delete and flush. - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-604} - * {@link https://github.com/apache/bookkeeper/issues/1757} - */ - @Test - public void testFlushDeleteRace() throws Exception { - newLedgerCache(); - final AtomicInteger rc = new AtomicInteger(0); - final LinkedBlockingQueue ledgerQ = new LinkedBlockingQueue<>(100); - final byte[] masterKey = "masterKey".getBytes(); - final long numLedgers = 1000; - final int numFlushers = 10; - final int numDeleters = 10; - final AtomicBoolean running = new AtomicBoolean(true); - Thread newLedgerThread = new Thread() { - public void run() { - try { - for (long i = 0; i < numLedgers && rc.get() == 0; i++) { - ledgerCache.setMasterKey(i, masterKey); - - ledgerCache.putEntryOffset(i, 1, 0); - ledgerQ.put(i); - } - for (int i = 0; i < numDeleters; ++i) { - ledgerQ.put(-1L); - } - } catch (Throwable e) { - rc.set(-1); - LOG.error("Exception in new ledger thread", e); - } - } - }; - newLedgerThread.start(); - - Thread[] flushThreads = new Thread[numFlushers]; - for (int i = 0; i < numFlushers; ++i) { - Thread flushThread = new Thread() { - public void run() { - try { - while (running.get()) { - ledgerCache.flushLedger(true); - } - } catch (Throwable e) { - rc.set(-1); - LOG.error("Exception in flush thread", e); - } - LOG.error("Shutting down flush thread"); - } - }; - flushThread.start(); - flushThreads[i] = flushThread; - } - - Thread[] deleteThreads = new Thread[numDeleters]; - for (int i = 0; i < numDeleters; ++i) { - Thread deleteThread = new Thread() { - public void run() { - try { - while (true) { - long id = ledgerQ.take(); - if (id == -1L) { - break; - } - LOG.info("Deleting {}", id); - ledgerCache.deleteLedger(id); - } - } catch (Throwable e) { - rc.set(-1); - LOG.error("Exception in delete thread", e); - } - } - }; - deleteThread.start(); - deleteThreads[i] = deleteThread; - } - - newLedgerThread.join(); - - for (Thread deleteThread : deleteThreads) { - deleteThread.join(); - } - - running.set(false); - for (Thread flushThread : flushThreads) { - flushThread.join(); - } - - assertEquals("Should have been no errors", rc.get(), 0); - for (long i = 0L; i < numLedgers; ++i) { - boolean gotError = false; - try { - LOG.error("Checking {}", i); - ledgerCache.getEntryOffset(i, 0); - } catch (NoLedgerException e) { - gotError = true; - } - if (!gotError) { - LOG.error("Ledger {} is still around", i); - fail("Found ledger " + i + ", which should have been removed"); - } - } - } - - // Mock SortedLedgerStorage to simulate flush failure (Dependency Fault Injection) - static class FlushTestSortedLedgerStorage extends SortedLedgerStorage { - final AtomicBoolean injectMemTableSizeLimitReached; - final AtomicBoolean injectFlushException; - final AtomicLong injectFlushExceptionForLedger; - final AtomicInteger numOfTimesFlushSnapshotCalled = new AtomicInteger(0); - static final long FORALLLEDGERS = -1; - ServerConfiguration conf; - StatsLogger statsLogger; - - public FlushTestSortedLedgerStorage() { - super(); - injectMemTableSizeLimitReached = new AtomicBoolean(); - injectFlushException = new AtomicBoolean(); - injectFlushExceptionForLedger = new AtomicLong(FORALLLEDGERS); - } - - public void setInjectMemTableSizeLimitReached(boolean setValue) { - injectMemTableSizeLimitReached.set(setValue); - } - - public void setInjectFlushException(boolean setValue, long ledgerId) { - injectFlushException.set(setValue); - injectFlushExceptionForLedger.set(ledgerId); - } - - public void incrementNumOfTimesFlushSnapshotCalled() { - numOfTimesFlushSnapshotCalled.incrementAndGet(); - } - - public int getNumOfTimesFlushSnapshotCalled() { - return numOfTimesFlushSnapshotCalled.get(); - } - - @Override - public void initialize(ServerConfiguration conf, - LedgerManager ledgerManager, - LedgerDirsManager ledgerDirsManager, - LedgerDirsManager indexDirsManager, - StatsLogger statsLogger, - ByteBufAllocator allocator) throws IOException { - super.initialize( - conf, - ledgerManager, - ledgerDirsManager, - indexDirsManager, - statsLogger, - allocator); - this.conf = conf; - this.statsLogger = statsLogger; - } - - @Override - public void setCheckpointSource(CheckpointSource checkpointSource) { - super.setCheckpointSource(checkpointSource); - if (this.memTable instanceof EntryMemTableWithParallelFlusher) { - this.memTable = new EntryMemTableWithParallelFlusher(conf, checkpointSource, statsLogger) { - @Override - boolean isSizeLimitReached() { - return (injectMemTableSizeLimitReached.get() || super.isSizeLimitReached()); - } - - @Override - long flushSnapshot(final SkipListFlusher flusher, Checkpoint checkpoint) throws IOException { - incrementNumOfTimesFlushSnapshotCalled(); - return super.flushSnapshot(flusher, checkpoint); - } - }; - } else { - this.memTable = new EntryMemTable(conf, checkpointSource, statsLogger) { - @Override - boolean isSizeLimitReached() { - return (injectMemTableSizeLimitReached.get() || super.isSizeLimitReached()); - } - - @Override - long flushSnapshot(final SkipListFlusher flusher, Checkpoint checkpoint) throws IOException { - incrementNumOfTimesFlushSnapshotCalled(); - return super.flushSnapshot(flusher, checkpoint); - } - }; - } - } - - @Override - public void process(long ledgerId, long entryId, ByteBuf buffer) throws IOException { - if (injectFlushException.get() && ((injectFlushExceptionForLedger.get() == FORALLLEDGERS) - || (injectFlushExceptionForLedger.get() == ledgerId))) { - throw new IOException("Injected Exception"); - } - super.process(ledgerId, entryId, buffer); - } - - // simplified memTable full callback. - @Override - public void onSizeLimitReached(final CheckpointSource.Checkpoint cp) throws IOException { - LOG.info("Reached size {}", cp); - // use synchronous way - try { - LOG.info("Started flushing mem table."); - memTable.flush(FlushTestSortedLedgerStorage.this); - } catch (IOException e) { - getStateManager().doTransitionToReadOnlyMode(); - LOG.error("Exception thrown while flushing skip list cache.", e); - } - } - - } - - @Test - public void testEntryMemTableFlushFailure() throws Exception { - File tmpDir = createTempDir("bkTest", ".dir"); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - int gcWaitTime = 1000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - conf.setLedgerStorageClass(FlushTestSortedLedgerStorage.class.getName()); - - Bookie bookie = new TestBookieImpl(conf); - FlushTestSortedLedgerStorage flushTestSortedLedgerStorage = - (FlushTestSortedLedgerStorage) bookie.getLedgerStorage(); - EntryMemTable memTable = flushTestSortedLedgerStorage.memTable; - - // this bookie.addEntry call is required. FileInfo for Ledger 1 would be created with this call. - // without the fileinfo, 'flushTestSortedLedgerStorage.addEntry' calls will fail - // because of BOOKKEEPER-965 change. - bookie.addEntry(generateEntry(1, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 2)); - assertFalse("Bookie is expected to be in ReadWrite mode", bookie.isReadOnly()); - assertTrue("EntryMemTable SnapShot is expected to be empty", memTable.snapshot.isEmpty()); - - // set flags, so that FlushTestSortedLedgerStorage simulates FlushFailure scenario - flushTestSortedLedgerStorage.setInjectMemTableSizeLimitReached(true); - flushTestSortedLedgerStorage.setInjectFlushException(true, FlushTestSortedLedgerStorage.FORALLLEDGERS); - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 2)); - - // since we simulated sizeLimitReached, snapshot shouldn't be empty - assertFalse("EntryMemTable SnapShot is not expected to be empty", memTable.snapshot.isEmpty()); - assertEquals("Flusher called", 1, flushTestSortedLedgerStorage.getNumOfTimesFlushSnapshotCalled()); - - // set the flags to false, so flush will succeed this time - flushTestSortedLedgerStorage.setInjectMemTableSizeLimitReached(false); - flushTestSortedLedgerStorage.setInjectFlushException(false, FlushTestSortedLedgerStorage.FORALLLEDGERS); - - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 3)); - // since we expect memtable flush to succeed, memtable snapshot should be empty - assertTrue("EntryMemTable SnapShot is expected to be empty, because of successful flush", - memTable.snapshot.isEmpty()); - } - - @Test - public void testSortedLedgerFlushFailure() throws Exception { - // most of the code is same to the testEntryMemTableFlushFailure - File tmpDir = createTempDir("bkTest", ".dir"); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - int gcWaitTime = 1000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime) - .setLedgerDirNames(new String[] { tmpDir.toString() }) - .setJournalDirName(tmpDir.toString()) - .setLedgerStorageClass(FlushTestSortedLedgerStorage.class.getName()); - - Bookie bookie = new TestBookieImpl(conf); - bookie.start(); - FlushTestSortedLedgerStorage flushTestSortedLedgerStorage = (FlushTestSortedLedgerStorage) bookie. - getLedgerStorage(); - EntryMemTable memTable = flushTestSortedLedgerStorage.memTable; - - bookie.addEntry(generateEntry(1, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 2)); - assertFalse("Bookie is expected to be in ReadWrite mode", bookie.isReadOnly()); - assertTrue("EntryMemTable SnapShot is expected to be empty", memTable.snapshot.isEmpty()); - - // set flags, so that FlushTestSortedLedgerStorage simulates FlushFailure scenario - flushTestSortedLedgerStorage.setInjectMemTableSizeLimitReached(true); - flushTestSortedLedgerStorage.setInjectFlushException(true, FlushTestSortedLedgerStorage.FORALLLEDGERS); - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 2)); - - // since we simulated sizeLimitReached, snapshot shouldn't be empty - assertFalse("EntryMemTable SnapShot is not expected to be empty", memTable.snapshot.isEmpty()); - // after flush failure, the bookie is set to readOnly - assertTrue("Bookie is expected to be in Read mode", bookie.isReadOnly()); - // write fail - CountDownLatch latch = new CountDownLatch(1); - bookie.addEntry(generateEntry(1, 3), false, new BookkeeperInternalCallbacks.WriteCallback(){ - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx){ - LOG.info("Write to bk succeed due to the bookie readOnly mode check is in the request parse step. " - + "In the addEntry step, we won't check bookie's mode"); - assertEquals(OK, rc); - latch.countDown(); - } - - }, null, "passwd".getBytes()); - latch.await(); - bookie.shutdown(); - - } - - private ByteBuf generateEntry(long ledger, long entry) { - byte[] data = ("ledger-" + ledger + "-" + entry).getBytes(); - ByteBuf bb = Unpooled.buffer(8 + 8 + data.length); - bb.writeLong(ledger); - bb.writeLong(entry); - bb.writeBytes(data); - return bb; - } - - @Test - public void testEntryMemTableParallelFlush() throws Exception { - int gcWaitTime = 1000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerDirNames(createAndGetLedgerDirs(1)); - conf.setLedgerStorageClass(FlushTestSortedLedgerStorage.class.getName()); - // enable entrylog per ledger - conf.setEntryLogPerLedgerEnabled(true); - - Bookie bookie = new TestBookieImpl(conf); - FlushTestSortedLedgerStorage flushTestSortedLedgerStorage = - (FlushTestSortedLedgerStorage) bookie.getLedgerStorage(); - EntryMemTable memTable = flushTestSortedLedgerStorage.memTable; - - /* - * this bookie.addEntry call is required. FileInfo for Ledger 1, 2, 3 - * would be created with this call. without the fileinfo, - * 'flushTestSortedLedgerStorage.addEntry' calls will fail because of - * BOOKKEEPER-965 change. - */ - bookie.addEntry(generateEntry(1, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - bookie.addEntry(generateEntry(2, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - bookie.addEntry(generateEntry(3, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 2)); - flushTestSortedLedgerStorage.addEntry(generateEntry(2, 2)); - flushTestSortedLedgerStorage.addEntry(generateEntry(3, 2)); - - assertTrue("EntryMemTable SnapShot is expected to be empty", memTable.snapshot.isEmpty()); - assertFalse("EntryMemTable is not expected to be empty", memTable.isEmpty()); - - // inject MemTableSizeLimitReached, so entrymemtable will be flushed - flushTestSortedLedgerStorage.setInjectMemTableSizeLimitReached(true); - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 3)); - - // since we simulated sizeLimitReached, snapshot should have been created and flushed - assertTrue("EntryMemTable SnapShot is expected to be empty", memTable.snapshot.isEmpty()); - assertEquals("Flusher called", 1, flushTestSortedLedgerStorage.getNumOfTimesFlushSnapshotCalled()); - } - - @Test - public void testEntryMemTableParallelFlushWithFlushException() throws Exception { - int gcWaitTime = 1000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerDirNames(createAndGetLedgerDirs(1)); - conf.setLedgerStorageClass(FlushTestSortedLedgerStorage.class.getName()); - // enable entrylog per ledger - conf.setEntryLogPerLedgerEnabled(true); - - Bookie bookie = new TestBookieImpl(conf); - FlushTestSortedLedgerStorage flushTestSortedLedgerStorage = - (FlushTestSortedLedgerStorage) bookie.getLedgerStorage(); - EntryMemTable memTable = flushTestSortedLedgerStorage.memTable; - - /* - * this bookie.addEntry call is required. FileInfo for Ledger 1, 2, 3 - * would be created with this call. without the fileinfo, - * 'flushTestSortedLedgerStorage.addEntry' calls will fail because of - * BOOKKEEPER-965 change. - */ - bookie.addEntry(generateEntry(1, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - bookie.addEntry(generateEntry(2, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - bookie.addEntry(generateEntry(3, 1), false, new BookieImpl.NopWriteCallback(), null, "passwd".getBytes()); - - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 4)); - flushTestSortedLedgerStorage.addEntry(generateEntry(2, 4)); - flushTestSortedLedgerStorage.addEntry(generateEntry(3, 4)); - - // inject MemTableSizeLimitReached and FlushException, so entrymemtable flush will fail - flushTestSortedLedgerStorage.setInjectMemTableSizeLimitReached(true); - flushTestSortedLedgerStorage.setInjectFlushException(true, 1L); - - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 5)); - // since we simulate FlushException, memtable snapshot should not be empty - assertFalse("EntryMemTable SnapShot is not expected to be empty", memTable.snapshot.isEmpty()); - assertEquals("Flusher called", 1, flushTestSortedLedgerStorage.getNumOfTimesFlushSnapshotCalled()); - - flushTestSortedLedgerStorage.setInjectFlushException(false, FlushTestSortedLedgerStorage.FORALLLEDGERS); - flushTestSortedLedgerStorage.addEntry(generateEntry(1, 5)); - /* - * since MemTableSizeLimitReached is already set to true, and flush - * exception is disabled, this time memtable snapshot should be flushed - */ - assertTrue("EntryMemTable SnapShot is expected to be empty", memTable.snapshot.isEmpty()); - assertEquals("Flusher called", 2, flushTestSortedLedgerStorage.getNumOfTimesFlushSnapshotCalled()); - } - - String[] createAndGetLedgerDirs(int numOfLedgerDirs) throws IOException { - File ledgerDir; - File curDir; - String[] ledgerDirsPath = new String[numOfLedgerDirs]; - for (int i = 0; i < numOfLedgerDirs; i++) { - ledgerDir = createTempDir("bkTest", ".dir"); - curDir = BookieImpl.getCurrentDirectory(ledgerDir); - BookieImpl.checkDirectoryStructure(curDir); - ledgerDirsPath[i] = ledgerDir.getAbsolutePath(); - } - return ledgerDirsPath; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerDirsManagerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerDirsManagerTest.java deleted file mode 100644 index d6e01cec457..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerDirsManagerTest.java +++ /dev/null @@ -1,662 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; - -import java.io.File; -import java.io.IOException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.bookkeeper.bookie.LedgerDirsManager.LedgerDirsListener; -import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; -import org.apache.bookkeeper.common.testing.executors.MockExecutorController; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.Gauge; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Test LedgerDirsManager. - */ -@RunWith(MockitoJUnitRunner.class) -public class LedgerDirsManagerTest { - - ServerConfiguration conf; - File curDir; - LedgerDirsManager dirsManager; - LedgerDirsMonitor ledgerMonitor; - MockDiskChecker mockDiskChecker; - private TestStatsProvider statsProvider; - private TestStatsProvider.TestStatsLogger statsLogger; - int diskCheckInterval = 1000; - float threshold = 0.5f; - float warnThreshold = 0.5f; - - final List tempDirs = new ArrayList(); - - // Thread used by monitor - ScheduledExecutorService executor; - MockExecutorController executorController; - MockedStatic executorsMockedStatic; - - File createTempDir(String prefix, String suffix) throws IOException { - File dir = IOUtils.createTempDir(prefix, suffix); - tempDirs.add(dir); - return dir; - } - - @Before - public void setUp() throws Exception { - executorsMockedStatic = mockStatic(Executors.class); - - File tmpDir = createTempDir("bkTest", ".dir"); - curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - conf.setDiskLowWaterMarkUsageThreshold(conf.getDiskUsageThreshold()); - conf.setDiskCheckInterval(diskCheckInterval); - conf.setIsForceGCAllowWhenNoSpace(true); - conf.setMinUsableSizeForEntryLogCreation(Long.MIN_VALUE); - - executor = mock(ScheduledExecutorService.class); - executorController = new MockExecutorController() - .controlScheduleAtFixedRate(executor, 10); - executorsMockedStatic.when(()->Executors.newSingleThreadScheduledExecutor(any())).thenReturn(executor); - - mockDiskChecker = new MockDiskChecker(threshold, warnThreshold); - statsProvider = new TestStatsProvider(); - statsLogger = statsProvider.getStatsLogger("test"); - dirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), statsLogger); - ledgerMonitor = new LedgerDirsMonitor(conf, - mockDiskChecker, Collections.singletonList(dirsManager)); - ledgerMonitor.init(); - } - - @After - public void tearDown() throws Exception { - executorsMockedStatic.close(); - ledgerMonitor.shutdown(); - for (File dir : tempDirs) { - FileUtils.deleteDirectory(dir); - } - tempDirs.clear(); - } - - @Test - public void testGetWritableDir() throws Exception { - try { - List writeDirs = dirsManager.getWritableLedgerDirs(); - assertTrue("Must have a writable ledgerDir", writeDirs.size() > 0); - } catch (NoWritableLedgerDirException nwlde) { - fail("We should have a writable ledgerDir"); - } - } - - @Test - public void testPickWritableDirExclusive() throws Exception { - try { - dirsManager.pickRandomWritableDir(curDir); - fail("Should not reach here due to there is no writable ledger dir."); - } catch (NoWritableLedgerDirException nwlde) { - // expected to fail with no writable ledger dir - assertTrue(true); - } - } - - @Test - public void testNoWritableDir() throws Exception { - try { - dirsManager.addToFilledDirs(curDir); - dirsManager.pickRandomWritableDir(); - fail("Should not reach here due to there is no writable ledger dir."); - } catch (NoWritableLedgerDirException nwlde) { - // expected to fail with no writable ledger dir - assertEquals("Should got NoWritableLedgerDirException w/ 'All ledger directories are non writable'.", - "All ledger directories are non writable", nwlde.getMessage()); - } - } - - @Test - public void testGetWritableDirForLog() throws Exception { - List writeDirs; - try { - dirsManager.addToFilledDirs(curDir); - dirsManager.getWritableLedgerDirs(); - fail("Should not reach here due to there is no writable ledger dir."); - } catch (NoWritableLedgerDirException nwlde) { - // expected to fail with no writable ledger dir - // Now make sure we can get one for log - try { - writeDirs = dirsManager.getWritableLedgerDirsForNewLog(); - assertTrue("Must have a writable ledgerDir", writeDirs.size() > 0); - } catch (NoWritableLedgerDirException e) { - fail("We should have a writeble ledgerDir"); - } - } - } - - @Test - public void testGetWritableDirForLogNoEnoughDiskSpace() throws Exception { - conf.setMinUsableSizeForEntryLogCreation(curDir.getUsableSpace() + 1024); - dirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), statsLogger); - try { - dirsManager.addToFilledDirs(curDir); - dirsManager.getWritableLedgerDirs(); - fail("Should not reach here due to there is no writable ledger dir."); - } catch (NoWritableLedgerDirException nwlde) { - // expected to fail with no writable ledger dir - // Now make sure we can get one for log - try { - dirsManager.getWritableLedgerDirsForNewLog(); - fail("Should not reach here due to there is no enough disk space left"); - } catch (NoWritableLedgerDirException e) { - // expected. - } - } - } - - @Test - public void testLedgerDirsMonitorDuringTransition() throws Exception { - testLedgerDirsMonitorDuringTransition(true); - } - - @Test - public void testHighPriorityWritesDisallowedDuringTransition() throws Exception { - testLedgerDirsMonitorDuringTransition(false); - } - - private void testLedgerDirsMonitorDuringTransition(boolean highPriorityWritesAllowed) throws Exception { - if (!highPriorityWritesAllowed) { - ledgerMonitor.shutdown(); - conf.setMinUsableSizeForHighPriorityWrites(curDir.getUsableSpace() + 1024); - dirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), statsLogger); - ledgerMonitor = new LedgerDirsMonitor(conf, mockDiskChecker, Collections.singletonList(dirsManager)); - ledgerMonitor.init(); - } - - MockLedgerDirsListener mockLedgerDirsListener = new MockLedgerDirsListener(); - dirsManager.addLedgerDirsListener(mockLedgerDirsListener); - ledgerMonitor.start(); - - assertFalse(mockLedgerDirsListener.readOnly); - assertTrue(mockLedgerDirsListener.highPriorityWritesAllowed); - - mockDiskChecker.setUsage(threshold + 0.05f); - executorController.advance(Duration.ofMillis(diskCheckInterval)); - - assertTrue(mockLedgerDirsListener.readOnly); - assertEquals(highPriorityWritesAllowed, mockLedgerDirsListener.highPriorityWritesAllowed); - - mockDiskChecker.setUsage(threshold - 0.05f); - executorController.advance(Duration.ofMillis(diskCheckInterval)); - - assertFalse(mockLedgerDirsListener.readOnly); - assertTrue(mockLedgerDirsListener.highPriorityWritesAllowed); - } - - @Test - public void testIsReadOnlyModeOnAnyDiskFullEnabled() throws Exception { - testAnyLedgerFullTransitToReadOnly(true); - testAnyLedgerFullTransitToReadOnly(false); - } - - public void testAnyLedgerFullTransitToReadOnly(boolean isReadOnlyModeOnAnyDiskFullEnabled) throws Exception { - ledgerMonitor.shutdown(); - - final float nospace = 0.90f; - final float lwm = 0.80f; - HashMap usageMap; - - File tmpDir1 = createTempDir("bkTest", ".dir"); - File curDir1 = BookieImpl.getCurrentDirectory(tmpDir1); - BookieImpl.checkDirectoryStructure(curDir1); - - File tmpDir2 = createTempDir("bkTest", ".dir"); - File curDir2 = BookieImpl.getCurrentDirectory(tmpDir2); - BookieImpl.checkDirectoryStructure(curDir2); - - conf.setDiskUsageThreshold(nospace); - conf.setDiskLowWaterMarkUsageThreshold(lwm); - conf.setDiskUsageWarnThreshold(nospace); - conf.setReadOnlyModeOnAnyDiskFullEnabled(isReadOnlyModeOnAnyDiskFullEnabled); - conf.setLedgerDirNames(new String[] { tmpDir1.toString(), tmpDir2.toString() }); - - mockDiskChecker = new MockDiskChecker(nospace, warnThreshold); - dirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), statsLogger); - ledgerMonitor = new LedgerDirsMonitor(conf, mockDiskChecker, Collections.singletonList(dirsManager)); - usageMap = new HashMap<>(); - usageMap.put(curDir1, 0.1f); - usageMap.put(curDir2, 0.1f); - mockDiskChecker.setUsageMap(usageMap); - ledgerMonitor.init(); - final MockLedgerDirsListener mockLedgerDirsListener = new MockLedgerDirsListener(); - dirsManager.addLedgerDirsListener(mockLedgerDirsListener); - ledgerMonitor.start(); - - Thread.sleep((diskCheckInterval * 2) + 100); - assertFalse(mockLedgerDirsListener.readOnly); - - if (isReadOnlyModeOnAnyDiskFullEnabled) { - setUsageAndThenVerify(curDir1, 0.1f, curDir2, nospace + 0.05f, mockDiskChecker, - mockLedgerDirsListener, true); - setUsageAndThenVerify(curDir1, nospace + 0.05f, curDir2, 0.1f, mockDiskChecker, - mockLedgerDirsListener, true); - setUsageAndThenVerify(curDir1, nospace + 0.05f, curDir2, nospace + 0.05f, mockDiskChecker, - mockLedgerDirsListener, true); - setUsageAndThenVerify(curDir1, nospace - 0.30f, curDir2, nospace + 0.05f, mockDiskChecker, - mockLedgerDirsListener, true); - setUsageAndThenVerify(curDir1, nospace - 0.20f, curDir2, nospace - 0.20f, mockDiskChecker, - mockLedgerDirsListener, false); - } else { - setUsageAndThenVerify(curDir1, 0.1f, curDir2, 0.1f, mockDiskChecker, - mockLedgerDirsListener, false); - setUsageAndThenVerify(curDir1, 0.1f, curDir2, nospace + 0.05f, mockDiskChecker, - mockLedgerDirsListener, false); - setUsageAndThenVerify(curDir1, nospace + 0.05f, curDir2, 0.1f, mockDiskChecker, - mockLedgerDirsListener, false); - setUsageAndThenVerify(curDir1, nospace + 0.05f, curDir2, nospace + 0.05f, mockDiskChecker, - mockLedgerDirsListener, true); - setUsageAndThenVerify(curDir1, nospace - 0.30f, curDir2, nospace + 0.05f, mockDiskChecker, - mockLedgerDirsListener, false); - setUsageAndThenVerify(curDir1, nospace - 0.20f, curDir2, nospace - 0.20f, mockDiskChecker, - mockLedgerDirsListener, false); - } - } - - @Test - public void testLedgerDirsMonitorHandlingLowWaterMark() throws Exception { - ledgerMonitor.shutdown(); - - final float warn = 0.90f; - final float nospace = 0.98f; - final float lwm = (warn + nospace) / 2; - final float lwm2warn = (warn + lwm) / 2; - final float lwm2nospace = (lwm + nospace) / 2; - final float nospaceExceeded = nospace + 0.005f; - - conf.setDiskUsageThreshold(nospace); - conf.setDiskLowWaterMarkUsageThreshold(lwm); - conf.setDiskUsageWarnThreshold(warn); - - mockDiskChecker = new MockDiskChecker(nospace, warnThreshold); - dirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - ledgerMonitor = new LedgerDirsMonitor(conf, mockDiskChecker, Collections.singletonList(dirsManager)); - ledgerMonitor.init(); - final MockLedgerDirsListener mockLedgerDirsListener = new MockLedgerDirsListener(); - dirsManager.addLedgerDirsListener(mockLedgerDirsListener); - ledgerMonitor.start(); - - executorController.advance(Duration.ofMillis(diskCheckInterval)); - assertFalse(mockLedgerDirsListener.readOnly); - - // go above LWM but below threshold - // should still be writable - mockDiskChecker.setUsage(lwm2nospace); - executorController.advance(Duration.ofMillis(diskCheckInterval)); - assertFalse(mockLedgerDirsListener.readOnly); - - // exceed the threshold, should go to readonly - mockDiskChecker.setUsage(nospaceExceeded); - executorController.advance(Duration.ofMillis(diskCheckInterval)); - assertTrue(mockLedgerDirsListener.readOnly); - - // drop below threshold but above LWM - // should stay read-only - mockDiskChecker.setUsage(lwm2nospace); - executorController.advance(Duration.ofMillis(diskCheckInterval)); - assertTrue(mockLedgerDirsListener.readOnly); - - // drop below LWM - // should become writable - mockDiskChecker.setUsage(lwm2warn); - executorController.advance(Duration.ofMillis(diskCheckInterval)); - assertFalse(mockLedgerDirsListener.readOnly); - - // go above LWM but below threshold - // should still be writable - mockDiskChecker.setUsage(lwm2nospace); - executorController.advance(Duration.ofMillis(diskCheckInterval)); - assertFalse(mockLedgerDirsListener.readOnly); - } - - @Test - public void testLedgerDirsMonitorHandlingWithMultipleLedgerDirectories() throws Exception { - ledgerMonitor.shutdown(); - - final float nospace = 0.90f; - final float lwm = 0.80f; - HashMap usageMap; - - File tmpDir1 = createTempDir("bkTest", ".dir"); - File curDir1 = BookieImpl.getCurrentDirectory(tmpDir1); - BookieImpl.checkDirectoryStructure(curDir1); - - File tmpDir2 = createTempDir("bkTest", ".dir"); - File curDir2 = BookieImpl.getCurrentDirectory(tmpDir2); - BookieImpl.checkDirectoryStructure(curDir2); - - conf.setDiskUsageThreshold(nospace); - conf.setDiskLowWaterMarkUsageThreshold(lwm); - conf.setDiskUsageWarnThreshold(nospace); - conf.setLedgerDirNames(new String[] { tmpDir1.toString(), tmpDir2.toString() }); - - mockDiskChecker = new MockDiskChecker(nospace, warnThreshold); - dirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), - statsLogger); - ledgerMonitor = new LedgerDirsMonitor(conf, mockDiskChecker, Collections.singletonList(dirsManager)); - usageMap = new HashMap(); - usageMap.put(curDir1, 0.1f); - usageMap.put(curDir2, 0.1f); - mockDiskChecker.setUsageMap(usageMap); - ledgerMonitor.init(); - final MockLedgerDirsListener mockLedgerDirsListener = new MockLedgerDirsListener(); - dirsManager.addLedgerDirsListener(mockLedgerDirsListener); - ledgerMonitor.start(); - - Thread.sleep((diskCheckInterval * 2) + 100); - assertFalse(mockLedgerDirsListener.readOnly); - - // go above LWM but below threshold - // should still be writable - setUsageAndThenVerify(curDir1, lwm + 0.05f, curDir2, lwm + 0.05f, mockDiskChecker, mockLedgerDirsListener, - false); - - // one dir usagespace above storagethreshold, another dir below storagethreshold - // should still be writable - setUsageAndThenVerify(curDir1, nospace + 0.02f, curDir2, nospace - 0.05f, mockDiskChecker, - mockLedgerDirsListener, false); - - // should remain readonly - setUsageAndThenVerify(curDir1, nospace + 0.05f, curDir2, nospace + 0.02f, mockDiskChecker, - mockLedgerDirsListener, true); - - // bring the disk usages to less than the threshold, - // but more than the LWM. - // should still be readonly - setUsageAndThenVerify(curDir1, nospace - 0.05f, curDir2, nospace - 0.05f, mockDiskChecker, - mockLedgerDirsListener, true); - - // bring one dir diskusage to less than lwm, - // the other dir to be more than lwm, but the - // overall diskusage to be more than lwm - // should still be readonly - setUsageAndThenVerify(curDir1, lwm - 0.03f, curDir2, lwm + 0.07f, mockDiskChecker, mockLedgerDirsListener, - true); - - // bring one dir diskusage to much less than lwm, - // the other dir to be more than storage threahold, but the - // overall diskusage is less than lwm - // should goto readwrite - setUsageAndThenVerify(curDir1, lwm - 0.17f, curDir2, nospace + 0.03f, mockDiskChecker, mockLedgerDirsListener, - false); - assertEquals("Only one LedgerDir should be writable", 1, dirsManager.getWritableLedgerDirs().size()); - - // bring both the dirs below lwm - // should still be readwrite - setUsageAndThenVerify(curDir1, lwm - 0.03f, curDir2, lwm - 0.02f, mockDiskChecker, mockLedgerDirsListener, - false); - assertEquals("Both the LedgerDirs should be writable", 2, dirsManager.getWritableLedgerDirs().size()); - - // bring both the dirs above lwm but < threshold - // should still be readwrite - setUsageAndThenVerify(curDir1, lwm + 0.02f, curDir2, lwm + 0.08f, mockDiskChecker, mockLedgerDirsListener, - false); - } - - @Test - public void testLedgerDirsMonitorStartReadOnly() throws Exception { - ledgerMonitor.shutdown(); - - final float nospace = 0.90f; - final float lwm = 0.80f; - - File tmpDir1 = createTempDir("bkTest", ".dir"); - File curDir1 = BookieImpl.getCurrentDirectory(tmpDir1); - BookieImpl.checkDirectoryStructure(curDir1); - - File tmpDir2 = createTempDir("bkTest", ".dir"); - File curDir2 = BookieImpl.getCurrentDirectory(tmpDir2); - BookieImpl.checkDirectoryStructure(curDir2); - - conf.setDiskUsageThreshold(nospace); - conf.setDiskLowWaterMarkUsageThreshold(lwm); - conf.setDiskUsageWarnThreshold(nospace); - conf.setLedgerDirNames(new String[] { tmpDir1.toString(), tmpDir2.toString() }); - - // Both disks are out of space at the start. - HashMap usageMap = new HashMap<>(); - usageMap.put(curDir1, nospace + 0.05f); - usageMap.put(curDir2, nospace + 0.05f); - - mockDiskChecker = new MockDiskChecker(nospace, warnThreshold); - mockDiskChecker.setUsageMap(usageMap); - dirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()), - statsLogger); - - ledgerMonitor = new LedgerDirsMonitor(conf, mockDiskChecker, Collections.singletonList(dirsManager)); - try { - ledgerMonitor.init(); - fail("NoWritableLedgerDirException expected"); - } catch (NoWritableLedgerDirException exception) { - // ok - } - final MockLedgerDirsListener mockLedgerDirsListener = new MockLedgerDirsListener(); - dirsManager.addLedgerDirsListener(mockLedgerDirsListener); - ledgerMonitor.start(); - - Thread.sleep((diskCheckInterval * 2) + 100); - verifyUsage(curDir1, nospace + 0.05f, curDir2, nospace + 0.05f, mockLedgerDirsListener, true); - } - - @Test - public void testValidateLwmThreshold() { - final ServerConfiguration configuration = TestBKConfiguration.newServerConfiguration(); - // check failed because diskSpaceThreshold < diskSpaceLwmThreshold - configuration.setDiskUsageThreshold(0.65f); - configuration.setDiskLowWaterMarkUsageThreshold(0.90f); - try { - new LedgerDirsMonitor(configuration, mockDiskChecker, Collections.singletonList(dirsManager)); - fail("diskSpaceThreshold < diskSpaceLwmThreshold, should be failed."); - } catch (Exception e) { - assertTrue(e.getMessage().contains("diskSpaceThreshold >= diskSpaceLwmThreshold")); - } - - // check failed because diskSpaceThreshold = 0 and diskUsageLwmThreshold = 1 - configuration.setDiskUsageThreshold(0f); - configuration.setDiskLowWaterMarkUsageThreshold(1f); - try { - new LedgerDirsMonitor(configuration, mockDiskChecker, Collections.singletonList(dirsManager)); - fail("diskSpaceThreshold = 0 and diskUsageLwmThreshold = 1, should be failed."); - } catch (Exception e) { - assertTrue(e.getMessage().contains("Should be > 0 and < 1")); - } - - // check succeeded - configuration.setDiskUsageThreshold(0.95f); - configuration.setDiskLowWaterMarkUsageThreshold(0.90f); - new LedgerDirsMonitor(configuration, mockDiskChecker, Collections.singletonList(dirsManager)); - } - - private void setUsageAndThenVerify(File dir1, float dir1Usage, File dir2, float dir2Usage, - MockDiskChecker mockDiskChecker, MockLedgerDirsListener mockLedgerDirsListener, boolean verifyReadOnly) - throws InterruptedException { - HashMap usageMap = new HashMap(); - usageMap.put(dir1, dir1Usage); - usageMap.put(dir2, dir2Usage); - mockDiskChecker.setUsageMap(usageMap); - verifyUsage(dir1, dir1Usage, dir2, dir2Usage, mockLedgerDirsListener, verifyReadOnly); - } - - private void verifyUsage(File dir1, float dir1Usage, File dir2, float dir2Usage, - MockLedgerDirsListener mockLedgerDirsListener, boolean verifyReadOnly) { - executorController.advance(Duration.ofMillis(diskCheckInterval)); - - float sample1 = getGauge(dir1.getParent()).getSample().floatValue(); - float sample2 = getGauge(dir2.getParent()).getSample().floatValue(); - - assertEquals(mockLedgerDirsListener.readOnly, verifyReadOnly); - assertThat(sample1, equalTo(dir1Usage * 100f)); - assertThat(sample2, equalTo(dir2Usage * 100f)); - } - - private Gauge getGauge(String path) { - String gaugeName = String.format("test.dir_%s_usage", path.replace('/', '_')); - return statsProvider.getGauge(gaugeName); - } - - private class MockDiskChecker extends DiskChecker { - - private volatile float used; - private volatile Map usageMap = null; - - public MockDiskChecker(float threshold, float warnThreshold) { - super(threshold, warnThreshold); - used = 0f; - } - - @Override - public float checkDir(File dir) throws DiskErrorException, DiskOutOfSpaceException, DiskWarnThresholdException { - float dirUsage = getDirUsage(dir); - - if (dirUsage > getDiskUsageThreshold()) { - throw new DiskOutOfSpaceException("", dirUsage); - } - if (dirUsage > getDiskUsageWarnThreshold()) { - throw new DiskWarnThresholdException("", dirUsage); - } - return dirUsage; - } - - @Override - public float getTotalDiskUsage(List dirs) { - float accumulatedDiskUsage = 0f; - for (File dir : dirs) { - accumulatedDiskUsage += getDirUsage(dir); - } - return (accumulatedDiskUsage / dirs.size()); - } - - public float getDirUsage(File dir) { - float dirUsage; - if ((usageMap == null) || (!usageMap.containsKey(dir))) { - dirUsage = used; - } else { - dirUsage = usageMap.get(dir); - } - return dirUsage; - } - - public void setUsage(float usage) { - this.used = usage; - } - - public void setUsageMap(Map usageMap) { - this.usageMap = usageMap; - } - } - - private class MockLedgerDirsListener implements LedgerDirsListener { - - public volatile boolean highPriorityWritesAllowed; - public volatile boolean readOnly; - - public MockLedgerDirsListener() { - reset(); - } - - @Override - public void diskWritable(File disk) { - if (conf.isReadOnlyModeOnAnyDiskFullEnabled()) { - return; - } - readOnly = false; - highPriorityWritesAllowed = true; - } - - @Override - public void diskJustWritable(File disk) { - if (conf.isReadOnlyModeOnAnyDiskFullEnabled()) { - return; - } - readOnly = false; - highPriorityWritesAllowed = true; - } - - @Override - public void allDisksFull(boolean highPriorityWritesAllowed) { - this.readOnly = true; - this.highPriorityWritesAllowed = highPriorityWritesAllowed; - } - - @Override - public void anyDiskFull(boolean highPriorityWritesAllowed) { - if (conf.isReadOnlyModeOnAnyDiskFullEnabled()) { - this.readOnly = true; - this.highPriorityWritesAllowed = highPriorityWritesAllowed; - } - } - - @Override - public void allDisksWritable() { - this.readOnly = false; - this.highPriorityWritesAllowed = true; - } - - public void reset() { - readOnly = false; - highPriorityWritesAllowed = true; - } - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageCheckpointTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageCheckpointTest.java deleted file mode 100644 index c468d2c2dc6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageCheckpointTest.java +++ /dev/null @@ -1,737 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.when; - -import io.netty.buffer.PooledByteBufAllocator; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.time.Duration; -import java.util.Enumeration; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import org.apache.bookkeeper.bookie.EntryLogManagerForEntryLogPerLedger.BufferedLogChannelWithDirInfo; -import org.apache.bookkeeper.bookie.Journal.LastLogMark; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.testing.executors.MockExecutorController; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.bookkeeper.util.PortManager; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * LedgerStorageCheckpointTest. - */ -@RunWith(MockitoJUnitRunner.class) -public class LedgerStorageCheckpointTest { - private static final Logger LOG = LoggerFactory - .getLogger(LedgerStorageCheckpointTest.class); - - @Rule - public final TestName runtime = new TestName(); - - // ZooKeeper related variables - protected final ZooKeeperUtil zkUtil = new ZooKeeperUtil(); - - // BookKeeper related variables - protected final List tmpDirs = new LinkedList(); - - // ScheduledExecutorService used by SyncThread - MockExecutorController executorController; - private MockedStatic syncThreadMockedStatic; - private MockedStatic garbageCollectorThreadMockedStatic; - private MockedStatic sortedLedgerStorageMockedStatic; - - @Before - public void setUp() throws Exception { - LOG.info("Setting up test {}", getClass()); - - try { - // start zookeeper service - startZKCluster(); - } catch (Exception e) { - LOG.error("Error setting up", e); - throw e; - } - - sortedLedgerStorageMockedStatic = mockStatic(SortedLedgerStorage.class); - ScheduledExecutorService scheduledExecutorService = mock(ScheduledExecutorService.class); - executorController = new MockExecutorController() - .controlSubmit(scheduledExecutorService) - .controlExecute(scheduledExecutorService) - .controlScheduleAtFixedRate(scheduledExecutorService, 10); - when(scheduledExecutorService.awaitTermination(anyLong(), any(TimeUnit.class))).thenReturn(true); - sortedLedgerStorageMockedStatic.when(() -> SortedLedgerStorage.newScheduledExecutorService()) - .thenReturn(scheduledExecutorService); - - syncThreadMockedStatic = mockStatic(SyncThread.class, CALLS_REAL_METHODS); - syncThreadMockedStatic.when(() -> SyncThread.newExecutor()) - .thenReturn(scheduledExecutorService); - - garbageCollectorThreadMockedStatic = mockStatic(GarbageCollectorThread.class); - garbageCollectorThreadMockedStatic.when(() -> GarbageCollectorThread.newExecutor()) - .thenReturn(scheduledExecutorService); - } - - @After - public void tearDown() throws Exception { - LOG.info("TearDown"); - - sortedLedgerStorageMockedStatic.close(); - syncThreadMockedStatic.close(); - garbageCollectorThreadMockedStatic.close(); - - Exception tearDownException = null; - // stop zookeeper service - try { - stopZKCluster(); - } catch (Exception e) { - LOG.error("Got Exception while trying to stop ZKCluster", e); - tearDownException = e; - } - // cleanup temp dirs - try { - cleanupTempDirs(); - } catch (Exception e) { - LOG.error("Got Exception while trying to cleanupTempDirs", e); - tearDownException = e; - } - if (tearDownException != null) { - throw tearDownException; - } - } - - /** - * Start zookeeper cluster. - * - * @throws Exception - */ - protected void startZKCluster() throws Exception { - zkUtil.startCluster(); - } - - /** - * Stop zookeeper cluster. - * - * @throws Exception - */ - protected void stopZKCluster() throws Exception { - zkUtil.killCluster(); - } - - protected void cleanupTempDirs() throws Exception { - for (File f : tmpDirs) { - FileUtils.deleteDirectory(f); - } - } - - protected File createTempDir(String prefix, String suffix) throws IOException { - File dir = IOUtils.createTempDir(prefix, suffix); - tmpDirs.add(dir); - return dir; - } - - private LogMark readLastMarkFile(File lastMarkFile) throws IOException { - byte[] buff = new byte[16]; - ByteBuffer bb = ByteBuffer.wrap(buff); - LogMark rolledLogMark = new LogMark(); - FileInputStream fis = new FileInputStream(lastMarkFile); - int bytesRead = fis.read(buff); - fis.close(); - if (bytesRead != 16) { - throw new IOException("Couldn't read enough bytes from lastMark." + " Wanted " + 16 + ", got " + bytesRead); - } - bb.clear(); - rolledLogMark.readLogMark(bb); - return rolledLogMark; - } - - /* - * In this testcase, InterleavedLedgerStorage is used and validate if the - * checkpoint is called for every flushinterval period. - */ - @Test - public void testPeriodicCheckpointForInterleavedLedgerStorage() throws Exception { - testPeriodicCheckpointForLedgerStorage(InterleavedLedgerStorage.class.getName()); - } - - /* - * In this testcase, SortedLedgerStorage is used and validate if the - * checkpoint is called for every flushinterval period. - */ - @Test - public void testPeriodicCheckpointForSortedLedgerStorage() throws Exception { - testPeriodicCheckpointForLedgerStorage(SortedLedgerStorage.class.getName()); - } - - public void testPeriodicCheckpointForLedgerStorage(String ledgerStorageClassName) throws Exception { - File tmpDir = createTempDir("DiskCheck", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setZkTimeout(5000) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setAutoRecoveryDaemonEnabled(false) - .setFlushInterval(2000) - .setBookiePort(PortManager.nextFreePort()) - // entrylog per ledger is enabled - .setEntryLogPerLedgerEnabled(true) - .setLedgerStorageClass(ledgerStorageClassName); - Assert.assertEquals("Number of JournalDirs", 1, conf.getJournalDirs().length); - // we know there is only one ledgerDir - File ledgerDir = BookieImpl.getCurrentDirectories(conf.getLedgerDirs())[0]; - BookieServer server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, PooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkClient = new BookKeeper(clientConf); - - int numOfLedgers = 2; - int numOfEntries = 5; - byte[] dataBytes = "data".getBytes(); - - for (int i = 0; i < numOfLedgers; i++) { - int ledgerIndex = i; - LedgerHandle handle = bkClient.createLedgerAdv((long) i, 1, 1, 1, DigestType.CRC32, "passwd".getBytes(), - null); - for (int j = 0; j < numOfEntries; j++) { - handle.addEntry(j, dataBytes); - } - handle.close(); - } - - LastLogMark lastLogMarkAfterFirstSetOfAdds = ((BookieImpl) server.getBookie()).journals.get(0).getLastLogMark(); - LogMark curMarkAfterFirstSetOfAdds = lastLogMarkAfterFirstSetOfAdds.getCurMark(); - - File lastMarkFile = new File(ledgerDir, "lastMark"); - // lastMark file should be zero, because checkpoint hasn't happenend - LogMark logMarkFileBeforeCheckpoint = readLastMarkFile(lastMarkFile); - Assert.assertEquals("lastMarkFile before checkpoint should be zero", 0, - logMarkFileBeforeCheckpoint.compare(new LogMark())); - - // wait for flushInterval for SyncThread to do next iteration of checkpoint - executorController.advance(Duration.ofMillis(conf.getFlushInterval())); - /* - * since we have waited for more than flushInterval SyncThread should - * have checkpointed. if entrylogperledger is not enabled, then we - * checkpoint only when currentLog in EntryLogger is rotated. but if - * entrylogperledger is enabled, then we checkpoint for every - * flushInterval period - */ - Assert.assertTrue("lastMark file must be existing, because checkpoint should have happened", - lastMarkFile.exists()); - - LastLogMark lastLogMarkAfterCheckpoint = ((BookieImpl) server.getBookie()).journals.get(0).getLastLogMark(); - LogMark curMarkAfterCheckpoint = lastLogMarkAfterCheckpoint.getCurMark(); - - LogMark rolledLogMark = readLastMarkFile(lastMarkFile); - Assert.assertNotEquals("rolledLogMark should not be zero, since checkpoint has happenend", 0, - rolledLogMark.compare(new LogMark())); - /* - * Curmark should be equal before and after checkpoint, because we didnt - * add new entries during this period - */ - Assert.assertTrue("Curmark should be equal before and after checkpoint", - curMarkAfterCheckpoint.compare(curMarkAfterFirstSetOfAdds) == 0); - /* - * Curmark after checkpoint should be equal to rolled logmark, because - * we checkpointed - */ - Assert.assertTrue("Curmark after first set of adds should be equal to rolled logmark", - curMarkAfterCheckpoint.compare(rolledLogMark) == 0); - - // add more ledger/entries - for (int i = numOfLedgers; i < 2 * numOfLedgers; i++) { - int ledgerIndex = i; - LedgerHandle handle = bkClient.createLedgerAdv((long) i, 1, 1, 1, DigestType.CRC32, "passwd".getBytes(), - null); - for (int j = 0; j < numOfEntries; j++) { - handle.addEntry(j, dataBytes); - } - handle.close(); - } - - // wait for flushInterval for SyncThread to do next iteration of checkpoint - executorController.advance(Duration.ofMillis(conf.getFlushInterval())); - - LastLogMark lastLogMarkAfterSecondSetOfAdds = ((BookieImpl) server.getBookie()). - journals.get(0).getLastLogMark(); - LogMark curMarkAfterSecondSetOfAdds = lastLogMarkAfterSecondSetOfAdds.getCurMark(); - - rolledLogMark = readLastMarkFile(lastMarkFile); - /* - * Curmark after checkpoint should be equal to rolled logmark, because - * we checkpointed - */ - Assert.assertTrue("Curmark after second set of adds should be equal to rolled logmark", - curMarkAfterSecondSetOfAdds.compare(rolledLogMark) == 0); - - server.shutdown(); - bkClient.close(); - } - - /* - * In this testcase, InterleavedLedgerStorage is used, entrylogperledger is - * enabled and validate that when entrylog is rotated it doesn't do - * checkpoint. - */ - @Test - public void testCheckpointOfILSEntryLogIsRotatedWithELPLEnabled() throws Exception { - testCheckpointofILSWhenEntryLogIsRotated(true); - } - - /* - * In this testcase, InterleavedLedgerStorage is used, entrylogperledger is - * not enabled and validate that when entrylog is rotated it does - * checkpoint. - */ - @Test - public void testCheckpointOfILSEntryLogIsRotatedWithELPLDisabled() throws Exception { - testCheckpointofILSWhenEntryLogIsRotated(false); - } - - public void testCheckpointofILSWhenEntryLogIsRotated(boolean entryLogPerLedgerEnabled) throws Exception { - File tmpDir = createTempDir("DiskCheck", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setZkTimeout(5000) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setAutoRecoveryDaemonEnabled(false) - //set very high period for flushInterval - .setFlushInterval(30000) - .setBookiePort(PortManager.nextFreePort()) - // entrylog per ledger is enabled - .setEntryLogPerLedgerEnabled(entryLogPerLedgerEnabled) - .setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - - Assert.assertEquals("Number of JournalDirs", 1, conf.getJournalDirs().length); - // we know there is only one ledgerDir - File ledgerDir = BookieImpl.getCurrentDirectories(conf.getLedgerDirs())[0]; - BookieServer server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, PooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkClient = new BookKeeper(clientConf); - InterleavedLedgerStorage ledgerStorage = (InterleavedLedgerStorage) server.getBookie().getLedgerStorage(); - - int numOfEntries = 5; - byte[] dataBytes = "data".getBytes(); - - long ledgerId = 10; - LedgerHandle handle = bkClient.createLedgerAdv(ledgerId, 1, 1, 1, DigestType.CRC32, "passwd".getBytes(), null); - for (int j = 0; j < numOfEntries; j++) { - handle.addEntry(j, dataBytes); - } - handle.close(); - // simulate rolling entrylog - ((EntryLogManagerBase) ledgerStorage.getEntryLogger().getEntryLogManager()) - .createNewLog(ledgerId); - // sleep for a bit for checkpoint to do its task - executorController.advance(Duration.ofMillis(500)); - - File lastMarkFile = new File(ledgerDir, "lastMark"); - LogMark rolledLogMark = readLastMarkFile(lastMarkFile); - if (entryLogPerLedgerEnabled) { - Assert.assertEquals( - "rolledLogMark should be zero, since checkpoint" - + "shouldn't have happened when entryLog is rotated", - 0, rolledLogMark.compare(new LogMark())); - } else { - Assert.assertNotEquals("rolledLogMark shouldn't be zero, since checkpoint" - + "should have happened when entryLog is rotated", 0, rolledLogMark.compare(new LogMark())); - } - bkClient.close(); - server.shutdown(); - } - - /* - * In this testcase, SortedLedgerStorage is used, entrylogperledger is - * enabled and validate that when entrylog is rotated it doesn't do - * checkpoint. - */ - @Test - public void testCheckpointOfSLSEntryLogIsRotatedWithELPLEnabled() throws Exception { - testCheckpointOfSLSWhenEntryLogIsRotated(true); - } - - /* - * In this testcase, SortedLedgerStorage is used, entrylogperledger is - * not enabled and validate that when entrylog is rotated it does - * checkpoint. - */ - @Test - public void testCheckpointOfSLSEntryLogIsRotatedWithELPLDisabled() throws Exception { - testCheckpointOfSLSWhenEntryLogIsRotated(false); - } - - public void testCheckpointOfSLSWhenEntryLogIsRotated(boolean entryLogPerLedgerEnabled) throws Exception { - File tmpDir = createTempDir("DiskCheck", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setZkTimeout(5000) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setAutoRecoveryDaemonEnabled(false) - //set very high period for flushInterval - .setFlushInterval(30000) - .setBookiePort(PortManager.nextFreePort()) - // entrylog per ledger is enabled - .setEntryLogPerLedgerEnabled(entryLogPerLedgerEnabled) - .setLedgerStorageClass(SortedLedgerStorage.class.getName()) - // set very low skipListSizeLimit and entryLogSizeLimit to simulate log file rotation - .setSkipListSizeLimit(1 * 1000 * 1000) - .setEntryLogSizeLimit(2 * 1000 * 1000); - - Assert.assertEquals("Number of JournalDirs", 1, conf.getJournalDirs().length); - // we know there is only one ledgerDir - File ledgerDir = BookieImpl.getCurrentDirectories(conf.getLedgerDirs())[0]; - BookieServer server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, PooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkClient = new BookKeeper(clientConf); - - Random rand = new Random(); - byte[] dataBytes = new byte[10 * 1000]; - rand.nextBytes(dataBytes); - int numOfEntries = ((int) conf.getEntryLogSizeLimit() + (100 * 1000)) / dataBytes.length; - - LedgerHandle handle = bkClient.createLedgerAdv(10, 1, 1, 1, DigestType.CRC32, "passwd".getBytes(), null); - for (int j = 0; j < numOfEntries; j++) { - handle.addEntry(j, dataBytes); - } - handle.close(); - - // sleep for a bit for checkpoint to do its task - executorController.advance(Duration.ofMillis(500)); - - File lastMarkFile = new File(ledgerDir, "lastMark"); - LogMark rolledLogMark = readLastMarkFile(lastMarkFile); - if (entryLogPerLedgerEnabled) { - Assert.assertEquals( - "rolledLogMark should be zero, since checkpoint" - + "shouldn't have happened when entryLog is rotated", - 0, rolledLogMark.compare(new LogMark())); - } else { - Assert.assertNotEquals("rolledLogMark shouldn't be zero, since checkpoint" - + "should have happened when entryLog is rotated", 0, rolledLogMark.compare(new LogMark())); - } - bkClient.close(); - server.shutdown(); - } - - /* - * in this method it checks if entryLogPerLedger is enabled, then - * InterLeavedLedgerStorage.checkpoint flushes current activelog and flushes - * all rotatedlogs and closes them. - * - */ - @Test - public void testIfEntryLogPerLedgerEnabledCheckpointFlushesAllLogs() throws Exception { - File tmpDir = createTempDir("DiskCheck", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setZkTimeout(5000) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setAutoRecoveryDaemonEnabled(false) - //set flushInterval - .setFlushInterval(3000) - .setBookiePort(PortManager.nextFreePort()) - // entrylog per ledger is enabled - .setEntryLogPerLedgerEnabled(true) - .setLedgerStorageClass(InterleavedLedgerStorage.class.getName()) - // set setFlushIntervalInBytes to some very high number - .setFlushIntervalInBytes(10000000); - - Assert.assertEquals("Number of JournalDirs", 1, conf.getJournalDirs().length); - // we know there is only one ledgerDir - File ledgerDir = BookieImpl.getCurrentDirectories(conf.getLedgerDirs())[0]; - BookieServer server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, PooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkClient = new BookKeeper(clientConf); - InterleavedLedgerStorage ledgerStorage = (InterleavedLedgerStorage) server.getBookie().getLedgerStorage(); - DefaultEntryLogger entryLogger = ledgerStorage.entryLogger; - EntryLogManagerForEntryLogPerLedger entryLogManager = (EntryLogManagerForEntryLogPerLedger) entryLogger - .getEntryLogManager(); - - Random rand = new Random(); - int numOfEntries = 5; - byte[] dataBytes = "data".getBytes(); - - int numOfLedgers = 3; - long[] ledgerIds = new long[numOfLedgers]; - LedgerHandle handle; - for (int i = 0; i < numOfLedgers; i++) { - ledgerIds[i] = rand.nextInt(100000) + 1; - handle = bkClient.createLedgerAdv(ledgerIds[i], 1, 1, 1, DigestType.CRC32, "passwd".getBytes(), null); - for (int j = 0; j < numOfEntries; j++) { - handle.addEntry(j, dataBytes); - } - // simulate rolling entrylog - entryLogManager.createNewLog(ledgerIds[i]); - } - - Set copyOfCurrentLogsWithDirInfo = entryLogManager.getCopyOfCurrentLogs(); - for (BufferedLogChannelWithDirInfo currentLogWithDirInfo : copyOfCurrentLogsWithDirInfo) { - Assert.assertNotEquals("bytesWrittenSinceLastFlush shouldn't be zero", 0, - currentLogWithDirInfo.getLogChannel().getUnpersistedBytes()); - } - Assert.assertNotEquals("There should be logChannelsToFlush", 0, - entryLogManager.getRotatedLogChannels().size()); - - /* - * wait for atleast flushInterval period, so that checkpoint can happen. - */ - executorController.advance(Duration.ofMillis(conf.getFlushInterval())); - - /* - * since checkpoint happenend, there shouldn't be any logChannelsToFlush - * and bytesWrittenSinceLastFlush should be zero. - */ - List copyOfRotatedLogChannels = entryLogManager.getRotatedLogChannels(); - Assert.assertTrue("There shouldn't be logChannelsToFlush", - ((copyOfRotatedLogChannels == null) || (copyOfRotatedLogChannels.size() == 0))); - - copyOfCurrentLogsWithDirInfo = entryLogManager.getCopyOfCurrentLogs(); - for (BufferedLogChannelWithDirInfo currentLogWithDirInfo : copyOfCurrentLogsWithDirInfo) { - Assert.assertEquals("bytesWrittenSinceLastFlush should be zero", 0, - currentLogWithDirInfo.getLogChannel().getUnpersistedBytes()); - } - } - - static class MockInterleavedLedgerStorage extends InterleavedLedgerStorage { - @Override - public void shutdown() { - // During BookieServer shutdown this method will be called - // and we want it to be noop. - // do nothing - } - - @Override - public synchronized void flush() throws IOException { - // this method will be called by SyncThread.shutdown. - // During BookieServer shutdown we want this method to be noop - // do nothing - } - } - - /* - * This is complete end-to-end scenario. - * - * 1) This testcase uses MockInterleavedLedgerStorage, which extends - * InterleavedLedgerStorage but doesn't do anything when Bookie is shutdown. - * This is needed to simulate Bookie crash. - * 2) entryLogPerLedger is enabled - * 3) ledgers are created and entries are added. - * 4) wait for flushInterval period for checkpoint to complete - * 5) simulate bookie crash - * 6) delete the journal files and lastmark file - * 7) Now restart the Bookie - * 8) validate that the entries which were written can be read successfully. - */ - @Test - public void testCheckPointForEntryLoggerWithMultipleActiveEntryLogs() throws Exception { - File tmpDir = createTempDir("DiskCheck", "test"); - - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setZkTimeout(5000) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setAutoRecoveryDaemonEnabled(false) - .setFlushInterval(3000) - .setBookiePort(PortManager.nextFreePort()) - // entrylog per ledger is enabled - .setEntryLogPerLedgerEnabled(true) - .setLedgerStorageClass(MockInterleavedLedgerStorage.class.getName()); - - Assert.assertEquals("Number of JournalDirs", 1, conf.getJournalDirs().length); - // we know there is only one ledgerDir - File ledgerDir = BookieImpl.getCurrentDirectories(conf.getLedgerDirs())[0]; - BookieServer server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, PooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - final BookKeeper bkClient = new BookKeeper(clientConf); - - int numOfLedgers = 12; - int numOfEntries = 100; - byte[] dataBytes = "data".getBytes(); - AtomicBoolean receivedExceptionForAdd = new AtomicBoolean(false); - LongStream.range(0, numOfLedgers).parallel().mapToObj((ledgerId) -> { - LedgerHandle handle = null; - try { - handle = bkClient.createLedgerAdv(ledgerId, 1, 1, 1, DigestType.CRC32, "passwd".getBytes(), null); - } catch (BKException | InterruptedException exc) { - receivedExceptionForAdd.compareAndSet(false, true); - LOG.error("Got Exception while trying to create LedgerHandle for ledgerId: " + ledgerId, exc); - } - return handle; - }).forEach((writeHandle) -> { - IntStream.range(0, numOfEntries).forEach((entryId) -> { - try { - writeHandle.addEntry(entryId, dataBytes); - } catch (BKException | InterruptedException exc) { - receivedExceptionForAdd.compareAndSet(false, true); - LOG.error("Got Exception while trying to AddEntry of ledgerId: " + writeHandle.getId() - + " entryId: " + entryId, exc); - } - }); - try { - writeHandle.close(); - } catch (BKException | InterruptedException e) { - receivedExceptionForAdd.compareAndSet(false, true); - LOG.error("Got Exception while trying to close writeHandle of ledgerId: " + writeHandle.getId(), e); - } - }); - - Assert.assertFalse( - "There shouldn't be any exceptions while creating writeHandle and adding entries to writeHandle", - receivedExceptionForAdd.get()); - - executorController.advance(Duration.ofMillis(conf.getFlushInterval())); - // since we have waited for more than flushInterval SyncThread should have checkpointed. - // if entrylogperledger is not enabled, then we checkpoint only when currentLog in EntryLogger - // is rotated. but if entrylogperledger is enabled, then we checkpoint for every flushInterval period - File lastMarkFile = new File(ledgerDir, "lastMark"); - Assert.assertTrue("lastMark file must be existing, because checkpoint should have happened", - lastMarkFile.exists()); - LogMark rolledLogMark = readLastMarkFile(lastMarkFile); - Assert.assertNotEquals("rolledLogMark should not be zero, since checkpoint has happenend", 0, - rolledLogMark.compare(new LogMark())); - - bkClient.close(); - // here we are calling shutdown, but MockInterleavedLedgerStorage shudown/flush - // methods are noop, so entrylogger is not flushed as part of this shutdown - // here we are trying to simulate Bookie crash, but there is no way to - // simulate bookie abrupt crash - server.shutdown(); - - // delete journal files and lastMark, to make sure that we are not reading from - // Journal file - File[] journalDirs = conf.getJournalDirs(); - for (File journalDir : journalDirs) { - File journalDirectory = BookieImpl.getCurrentDirectory(journalDir); - List journalLogsId = Journal.listJournalIds(journalDirectory, null); - for (long journalId : journalLogsId) { - File journalFile = new File(journalDirectory, Long.toHexString(journalId) + ".txn"); - journalFile.delete(); - } - } - - // we know there is only one ledgerDir - lastMarkFile = new File(ledgerDir, "lastMark"); - lastMarkFile.delete(); - - // now we are restarting BookieServer - conf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, PooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - BookKeeper newBKClient = new BookKeeper(clientConf); - // since Bookie checkpointed successfully before shutdown/crash, - // we should be able to read from entryLogs though journal is deleted - - AtomicBoolean receivedExceptionForRead = new AtomicBoolean(false); - - LongStream.range(0, numOfLedgers).parallel().forEach((ledgerId) -> { - try { - LedgerHandle lh = newBKClient.openLedger(ledgerId, DigestType.CRC32, "passwd".getBytes()); - Enumeration entries = lh.readEntries(0, numOfEntries - 1); - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - byte[] readData = entry.getEntry(); - Assert.assertEquals("Ledger Entry Data should match", new String("data".getBytes()), - new String(readData)); - } - lh.close(); - } catch (BKException | InterruptedException e) { - receivedExceptionForRead.compareAndSet(false, true); - LOG.error("Got Exception while trying to read entries of ledger, ledgerId: " + ledgerId, e); - } - }); - Assert.assertFalse("There shouldn't be any exceptions while creating readHandle and while reading" - + "entries using readHandle", receivedExceptionForRead.get()); - - newBKClient.close(); - server.shutdown(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTest.java deleted file mode 100644 index fd1851703b1..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTest.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.PrimitiveIterator.OfLong; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; -import java.util.stream.IntStream; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.TestUtils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test ledger storage. - */ -public class LedgerStorageTest extends BookKeeperClusterTestCase { - public LedgerStorageTest() { - super(1); - } - - @Test - public void testLedgerDeleteNotification() throws Exception { - LedgerStorage ledgerStorage = serverByIndex(0).getBookie().getLedgerStorage(); - - long deletedLedgerId = 5; - ledgerStorage.setMasterKey(deletedLedgerId, new byte[0]); - - CountDownLatch counter = new CountDownLatch(1); - - ledgerStorage.registerLedgerDeletionListener(ledgerId -> { - assertEquals(deletedLedgerId, ledgerId); - - counter.countDown(); - }); - - ledgerStorage.deleteLedger(deletedLedgerId); - - counter.await(); - } - - @Test - public void testExplicitLacWriteToJournalWithValidVersions() throws Exception { - /* - * to persist explicitLac, journalFormatVersionToWrite should be atleast - * V6 and fileInfoFormatVersionToWrite should be atleast V1 - */ - testExplicitLacWriteToJournal(6, 1); - } - - @Test - public void testExplicitLacWriteToJournalWithOlderVersions() throws Exception { - /* - * to persist explicitLac, journalFormatVersionToWrite should be atleast - * V6 and fileInfoFormatVersionToWrite should be atleast V1 - */ - testExplicitLacWriteToJournal(5, 0); - } - - public void testExplicitLacWriteToJournal(int journalFormatVersionToWrite, int fileInfoFormatVersionToWrite) - throws Exception { - restartBookies(c -> { - c.setJournalFormatVersionToWrite(journalFormatVersionToWrite); - c.setFileInfoFormatVersionToWrite(fileInfoFormatVersionToWrite); - return c; - }); - - - ClientConfiguration confWithExplicitLAC = new ClientConfiguration(); - confWithExplicitLAC.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - /* - * enable explicitLacFlush by setting non-zero value for - * explictLacInterval - */ - int explictLacInterval = 100; - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - byte[] passwdBytes = "testPasswd".getBytes(); - confWithExplicitLAC.setExplictLacInterval(explictLacInterval); - - BookKeeper bkcWithExplicitLAC = new BookKeeper(confWithExplicitLAC); - - LedgerHandle wlh = bkcWithExplicitLAC.createLedger(1, 1, 1, digestType, passwdBytes); - long ledgerId = wlh.getId(); - int numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - LedgerHandle rlh = bkcWithExplicitLAC.openLedgerNoRecovery(ledgerId, digestType, passwdBytes); - - assertEquals("LAC of rlh", (long) numOfEntries - 2, rlh.getLastAddConfirmed()); - assertEquals("Read explicit LAC of rlh", (long) numOfEntries - 2, rlh.readExplicitLastConfirmed()); - - /* - * we need to wait for atleast 2 explicitlacintervals, since in - * writehandle for the first call lh.getExplicitLastAddConfirmed() will - * be < lh.getPiggyBackedLastAddConfirmed(), so it wont make explicit - * writelac in the first run - */ - long readExplicitLastConfirmed = TestUtils.waitUntilExplicitLacUpdated(rlh, numOfEntries - 1); - assertEquals("Read explicit LAC of rlh after wait for explicitlacflush", (numOfEntries - 1), - readExplicitLastConfirmed); - - ServerConfiguration newBookieConf = new ServerConfiguration(confByIndex(0)); - /* - * by reusing bookieServerConfig and setting metadataServiceUri to null - * we can create/start new Bookie instance using the same data - * (journal/ledger/index) of the existing BookeieServer for our testing - * purpose. - */ - newBookieConf.setMetadataServiceUri(null); - BookieImpl newbookie = new TestBookieImpl(newBookieConf); - /* - * since 'newbookie' uses the same data as original Bookie, it should be - * able to read journal of the original bookie and hence explicitLac buf - * entry written to Journal in the original bookie. - */ - newbookie.readJournal(); - ByteBuf explicitLacBuf = newbookie.getExplicitLac(ledgerId); - - if ((journalFormatVersionToWrite >= 6) && (fileInfoFormatVersionToWrite >= 1)) { - DigestManager digestManager = DigestManager.instantiate(ledgerId, passwdBytes, - BookKeeper.DigestType.toProtoDigestType(digestType), UnpooledByteBufAllocator.DEFAULT, - confWithExplicitLAC.getUseV2WireProtocol()); - long explicitLacPersistedInJournal = digestManager.verifyDigestAndReturnLac(explicitLacBuf); - assertEquals("explicitLac persisted in journal", (numOfEntries - 1), explicitLacPersistedInJournal); - } else { - assertEquals("explicitLac is not expected to be persisted, so it should be null", null, explicitLacBuf); - } - bkcWithExplicitLAC.close(); - } - - @Test - public void testExplicitLacWriteToFileInfoWithValidVersions() throws Exception { - /* - * to persist explicitLac, journalFormatVersionToWrite should be atleast - * V6 and fileInfoFormatVersionToWrite should be atleast V1 - */ - testExplicitLacWriteToFileInfo(6, 1); - } - - @Test - public void testExplicitLacWriteToFileInfoWithOlderVersions() throws Exception { - /* - * to persist explicitLac, journalFormatVersionToWrite should be atleast - * V6 and fileInfoFormatVersionToWrite should be atleast V1 - */ - testExplicitLacWriteToFileInfo(5, 0); - } - - public void testExplicitLacWriteToFileInfo(int journalFormatVersionToWrite, int fileInfoFormatVersionToWrite) - throws Exception { - restartBookies(c -> { - c.setJournalFormatVersionToWrite(journalFormatVersionToWrite); - c.setFileInfoFormatVersionToWrite(fileInfoFormatVersionToWrite); - return c; - }); - - ClientConfiguration confWithExplicitLAC = new ClientConfiguration(); - confWithExplicitLAC.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - /* - * enable explicitLacFlush by setting non-zero value for - * explictLacInterval - */ - int explictLacInterval = 100; - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - byte[] passwdBytes = "testPasswd".getBytes(); - confWithExplicitLAC.setExplictLacInterval(explictLacInterval); - - BookKeeper bkcWithExplicitLAC = new BookKeeper(confWithExplicitLAC); - - LedgerHandle wlh = bkcWithExplicitLAC.createLedger(1, 1, 1, digestType, passwdBytes); - long ledgerId = wlh.getId(); - int numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - LedgerHandle rlh = bkcWithExplicitLAC.openLedgerNoRecovery(ledgerId, digestType, passwdBytes); - - assertEquals("LAC of rlh", (long) numOfEntries - 2, rlh.getLastAddConfirmed()); - assertEquals("Read explicit LAC of rlh", (long) numOfEntries - 2, rlh.readExplicitLastConfirmed()); - - /* - * we need to wait for atleast 2 explicitlacintervals, since in - * writehandle for the first call lh.getExplicitLastAddConfirmed() will - * be < lh.getPiggyBackedLastAddConfirmed(), so it wont make explicit - * writelac in the first run - */ - long readExplicitLastConfirmed = TestUtils.waitUntilExplicitLacUpdated(rlh, numOfEntries - 1); - assertEquals("Read explicit LAC of rlh after wait for explicitlacflush", (numOfEntries - 1), - readExplicitLastConfirmed); - - /* - * flush ledgerStorage so that header of fileinfo is flushed. - */ - serverByIndex(0).getBookie().getLedgerStorage().flush(); - - ReadOnlyFileInfo fileInfo = getFileInfo(ledgerId, - BookieImpl.getCurrentDirectories(confByIndex(0).getLedgerDirs())); - fileInfo.readHeader(); - ByteBuf explicitLacBufReadFromFileInfo = fileInfo.getExplicitLac(); - - if ((journalFormatVersionToWrite >= 6) && (fileInfoFormatVersionToWrite >= 1)) { - DigestManager digestManager = DigestManager.instantiate(ledgerId, passwdBytes, - BookKeeper.DigestType.toProtoDigestType(digestType), UnpooledByteBufAllocator.DEFAULT, - confWithExplicitLAC.getUseV2WireProtocol()); - long explicitLacReadFromFileInfo = digestManager.verifyDigestAndReturnLac(explicitLacBufReadFromFileInfo); - assertEquals("explicitLac persisted in FileInfo", (numOfEntries - 1), explicitLacReadFromFileInfo); - } else { - assertEquals("explicitLac is not expected to be persisted, so it should be null", null, - explicitLacBufReadFromFileInfo); - } - - bkcWithExplicitLAC.close(); - } - - /** - * Get the ledger file of a specified ledger. - * - * @param ledgerId Ledger Id - * - * @return file object. - */ - private File getLedgerFile(long ledgerId, File[] indexDirectories) { - String ledgerName = IndexPersistenceMgr.getLedgerName(ledgerId); - File lf = null; - for (File d : indexDirectories) { - lf = new File(d, ledgerName); - if (lf.exists()) { - break; - } - lf = null; - } - return lf; - } - - /** - * Get FileInfo for a specified ledger. - * - * @param ledgerId Ledger Id - * @return read only file info instance - */ - ReadOnlyFileInfo getFileInfo(long ledgerId, File[] indexDirectories) throws IOException { - File ledgerFile = getLedgerFile(ledgerId, indexDirectories); - if (null == ledgerFile) { - throw new FileNotFoundException("No index file found for ledger " + ledgerId - + ". It may be not flushed yet."); - } - ReadOnlyFileInfo fi = new ReadOnlyFileInfo(ledgerFile, null); - fi.readHeader(); - return fi; - } - - @Test - public void testGetListOfEntriesOfLedger() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numOfBookies = bookieCount(); - int numOfEntries = 5; - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - BookKeeper bkc = new BookKeeper(conf); - LedgerHandle lh = bkc.createLedger(numOfBookies, numOfBookies, digestType, "testPasswd".getBytes()); - long lId = lh.getId(); - for (int i = 0; i < numOfEntries; i++) { - lh.addEntry("000".getBytes()); - } - - ServerConfiguration newBookieConf = new ServerConfiguration(confByIndex(0)); - /* - * by reusing bookieServerConfig and setting metadataServiceUri to null - * we can create/start new Bookie instance using the same data - * (journal/ledger/index) of the existing BookeieServer for our testing - * purpose. - */ - newBookieConf.setMetadataServiceUri(null); - BookieImpl newbookie = new TestBookieImpl(newBookieConf); - /* - * since 'newbookie' uses the same data as original Bookie, it should be - * able to read journal of the original bookie. - */ - newbookie.readJournal(); - - OfLong listOfEntriesItr = newbookie.getListOfEntriesOfLedger(lId); - ArrayList arrayList = new ArrayList(); - Consumer addMethod = arrayList::add; - listOfEntriesItr.forEachRemaining(addMethod); - - assertEquals("Num Of Entries", numOfEntries, arrayList.size()); - Assert.assertTrue("Iterator should be sorted", - IntStream.range(0, arrayList.size() - 1).allMatch(k -> arrayList.get(k) <= arrayList.get(k + 1))); - bkc.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTestBase.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTestBase.java deleted file mode 100644 index f483ceec4d6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTestBase.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie; - -import java.io.File; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TestName; - -/** - * Test the checkpoint logic in bookies. - */ -@Slf4j -public abstract class LedgerStorageTestBase { - - @Rule - public TestName testName = new TestName(); - - protected ServerConfiguration conf; - protected File journalDir, ledgerDir; - protected LedgerDirsManager ledgerDirsManager; - - private File createTempDir(String suffix) throws Exception { - File dir = File.createTempFile(testName.getMethodName(), suffix); - dir.delete(); - dir.mkdirs(); - return dir; - } - - protected LedgerStorageTestBase() { - conf = TestBKConfiguration.newServerConfiguration(); - } - - @Before - public void setUp() throws Exception { - journalDir = createTempDir("journal"); - ledgerDir = createTempDir("ledger"); - - // create current directories - BookieImpl.getCurrentDirectory(journalDir).mkdir(); - BookieImpl.getCurrentDirectory(ledgerDir).mkdir(); - - // build the configuration - conf.setMetadataServiceUri(null); - conf.setJournalDirName(journalDir.getPath()); - conf.setLedgerDirNames(new String[] { ledgerDir.getPath() }); - - // build the ledger monitor - DiskChecker checker = new DiskChecker( - conf.getDiskUsageThreshold(), - conf.getDiskUsageWarnThreshold()); - ledgerDirsManager = new LedgerDirsManager( - conf, - conf.getLedgerDirs(), - checker); - } - - @After - public void tearDown() throws Exception { - FileUtils.deleteDirectory(journalDir); - FileUtils.deleteDirectory(ledgerDir); - } - - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java deleted file mode 100644 index e1979dbdc4f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie; - -import com.google.common.util.concurrent.RateLimiter; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.List; -import java.util.Optional; -import java.util.PrimitiveIterator; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.common.util.Watcher; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.stats.StatsLogger; - -/** - * A mock for running tests that require ledger storage. - */ -public class MockLedgerStorage implements CompactableLedgerStorage { - - private static class LedgerInfo { - boolean limbo = false; - boolean fenced = false; - long lac = -1; - final byte[] masterKey; - - LedgerInfo(byte[] masterKey) { - this.masterKey = Arrays.copyOf(masterKey, masterKey.length); - } - - ConcurrentHashMap entries = new ConcurrentHashMap<>(); - } - - private final ConcurrentHashMap ledgers = new ConcurrentHashMap<>(); - private final EnumSet storageStateFlags = EnumSet.noneOf(StorageState.class); - private final List entryLocations = new ArrayList<>(); - - @Override - public void initialize(ServerConfiguration conf, - LedgerManager ledgerManager, - LedgerDirsManager ledgerDirsManager, - LedgerDirsManager indexDirsManager, - StatsLogger statsLogger, - ByteBufAllocator allocator) - throws IOException {} - - @Override - public void setStateManager(StateManager stateManager) {} - @Override - public void setCheckpointSource(CheckpointSource checkpointSource) {} - @Override - public void setCheckpointer(Checkpointer checkpointer) {} - - @Override - public void start() {} - @Override - public void shutdown() throws InterruptedException {} - - @Override - public boolean ledgerExists(long ledgerId) throws IOException { - return ledgers.containsKey(ledgerId); - } - - @Override - public boolean entryExists(long ledgerId, long entryId) throws IOException { - LedgerInfo info = ledgers.get(ledgerId); - if (info == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - return info != null && info.entries.containsKey(entryId); - } - - @Override - public boolean setFenced(long ledgerId) throws IOException { - AtomicBoolean ret = new AtomicBoolean(false); - LedgerInfo previous = ledgers.computeIfPresent(ledgerId, (ledgerId1, current) -> { - if (!current.fenced) { - current.fenced = true; - ret.set(true); - } else { - ret.set(false); - } - return current; - }); - if (previous == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - return ret.get(); - } - - @Override - public boolean isFenced(long ledgerId) throws IOException { - LedgerInfo info = ledgers.get(ledgerId); - if (info == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - return info != null && info.fenced; - } - - @Override - public void setLimboState(long ledgerId) throws IOException { - LedgerInfo previous = ledgers.computeIfPresent(ledgerId, (ledgerId1, current) -> { - current.limbo = true; - return current; - }); - if (previous == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - } - - @Override - public boolean hasLimboState(long ledgerId) throws IOException { - LedgerInfo info = ledgers.get(ledgerId); - if (info == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - return info.limbo; - } - @Override - public void clearLimboState(long ledgerId) throws IOException { - LedgerInfo previous = ledgers.computeIfPresent(ledgerId, (ledgerId1, current) -> { - current.limbo = false; - return current; - }); - if (previous == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - } - - @Override - public void setMasterKey(long ledgerId, byte[] masterKey) throws IOException { - LedgerInfo previous = ledgers.compute(ledgerId, (ledgerId1, current) -> { - if (current != null) { - return current; - } - return new LedgerInfo(masterKey); - }); - if (previous != null && !Arrays.equals(masterKey, previous.masterKey)) { - throw new IOException(BookieException.create(BookieException.Code.IllegalOpException)); - } - } - @Override - public byte[] readMasterKey(long ledgerId) throws IOException, BookieException { - LedgerInfo info = ledgers.get(ledgerId); - if (info == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - return Arrays.copyOf(info.masterKey, info.masterKey.length); - } - - public long extractLedgerId(ByteBuf entry) { - return entry.getLong(entry.readerIndex()); - } - - public long extractEntryId(ByteBuf entry) { - return entry.getLong(entry.readerIndex() + 8); - } - - public long extractLac(ByteBuf entry) { - return entry.getLong(entry.readerIndex() + 16); - - } - - @Override - public long addEntry(ByteBuf entry) throws IOException, BookieException { - ByteBuf copy = entry.retain().duplicate(); - long ledgerId = extractLedgerId(copy); - long entryId = extractEntryId(copy); - long lac = extractLac(copy); - - LedgerInfo previous = ledgers.computeIfPresent(ledgerId, (ledgerId1, current) -> { - if (lac > current.lac) { - current.lac = lac; - } - current.entries.put(entryId, copy); - return current; - }); - if (previous == null) { - throw new Bookie.NoLedgerException(ledgerId); - } - return entryId; - } - - @Override - public ByteBuf getEntry(long ledgerId, long entryId) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public long getLastAddConfirmed(long ledgerId) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public boolean waitForLastAddConfirmedUpdate( - long ledgerId, - long previousLAC, - Watcher watcher) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public void cancelWaitForLastAddConfirmedUpdate( - long ledgerId, - Watcher watcher) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public void flush() throws IOException { - // this is a noop, as we dont hit disk anyhow - } - - @Override - public void checkpoint(Checkpoint checkpoint) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public void deleteLedger(long ledgerId) throws IOException { - ledgers.remove(ledgerId); - } - - @Override - public void registerLedgerDeletionListener(LedgerDeletionListener listener) { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public void setExplicitLac(long ledgerId, ByteBuf lac) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public ByteBuf getExplicitLac(long ledgerId) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public LedgerStorage getUnderlyingLedgerStorage() { - return CompactableLedgerStorage.super.getUnderlyingLedgerStorage(); - } - - @Override - public void forceGC() { - CompactableLedgerStorage.super.forceGC(); - } - - @Override - public void forceGC(boolean forceMajor, boolean forceMinor) { - CompactableLedgerStorage.super.forceGC(forceMajor, forceMinor); - } - - public void suspendMinorGC() { - CompactableLedgerStorage.super.suspendMinorGC(); - } - - public void suspendMajorGC() { - CompactableLedgerStorage.super.suspendMajorGC(); - } - - public void resumeMinorGC() { - CompactableLedgerStorage.super.resumeMinorGC(); - } - - public void resumeMajorGC() { - CompactableLedgerStorage.super.suspendMajorGC(); - } - - public boolean isMajorGcSuspended() { - return CompactableLedgerStorage.super.isMajorGcSuspended(); - } - - public boolean isMinorGcSuspended() { - return CompactableLedgerStorage.super.isMinorGcSuspended(); - } - - @Override - public List localConsistencyCheck(Optional rateLimiter) throws IOException { - return CompactableLedgerStorage.super.localConsistencyCheck(rateLimiter); - } - - @Override - public boolean isInForceGC() { - return CompactableLedgerStorage.super.isInForceGC(); - } - - @Override - public List getGarbageCollectionStatus() { - return CompactableLedgerStorage.super.getGarbageCollectionStatus(); - } - - @Override - public PrimitiveIterator.OfLong getListOfEntriesOfLedger(long ledgerId) throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - @Override - public Iterable getActiveLedgersInRange(long firstLedgerId, long lastLedgerId) - throws IOException { - throw new UnsupportedOperationException("Not supported in mock, implement if you need it"); - } - - public List getUpdatedLocations() { - return entryLocations; - } - - @Override - public void updateEntriesLocations(Iterable locations) throws IOException { - synchronized (entryLocations) { - for (EntryLocation l : locations) { - entryLocations.add(l); - } - } - } - - @Override - public EnumSet getStorageStateFlags() throws IOException { - return storageStateFlags; - } - - @Override - public void setStorageStateFlag(StorageState flag) throws IOException { - storageStateFlags.add(flag); - } - - @Override - public void clearStorageStateFlag(StorageState flag) throws IOException { - storageStateFlags.remove(flag); - } - - @Override - public void flushEntriesLocationsIndex() throws IOException { } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockUncleanShutdownDetection.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockUncleanShutdownDetection.java deleted file mode 100644 index bf907e12091..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockUncleanShutdownDetection.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -/** - * Mock implementation of UncleanShutdownDetection. - */ -public class MockUncleanShutdownDetection implements UncleanShutdownDetection { - - private boolean startRegistered; - private boolean shutdownRegistered; - - @Override - public void registerStartUp() { - startRegistered = true; - } - - @Override - public void registerCleanShutdown() { - shutdownRegistered = true; - } - - @Override - public boolean lastShutdownWasUnclean() { - return startRegistered && !shutdownRegistered; - } - - public boolean getStartRegistered() { - return startRegistered; - } - - public boolean getShutdownRegistered() { - return shutdownRegistered; - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SingleBookieInitializationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SingleBookieInitializationTest.java deleted file mode 100644 index 11206b8cce9..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SingleBookieInitializationTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.bookie.BookieException.Code; -import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Test a single bookie at readonly mode. - */ -public class SingleBookieInitializationTest { - - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - - private File journalDir; - private File ledgerDir; - private ServerConfiguration conf; - private Bookie bookie; - - @Before - public void setUp() throws Exception { - this.journalDir = testDir.newFolder("journal"); - this.ledgerDir = testDir.newFolder("ledgers"); - - this.conf = TestBKConfiguration.newServerConfiguration(); - this.conf.setJournalDirsName(new String[] { journalDir.getAbsolutePath() }); - this.conf.setLedgerDirNames(new String[] { ledgerDir.getAbsolutePath() }); - this.conf.setMetadataServiceUri(null); - } - - @After - public void tearDown() throws Exception { - if (null != this.bookie) { - this.bookie.shutdown(); - } - } - - private static String generateDataString(long ledger, long entry) { - return ("ledger-" + ledger + "-" + entry); - } - - private static ByteBuf generateEntry(long ledger, long entry) { - byte[] data = generateDataString(ledger, entry).getBytes(); - ByteBuf bb = Unpooled.buffer(8 + 8 + data.length); - bb.writeLong(ledger); - bb.writeLong(entry); - bb.writeBytes(data); - return bb; - } - - @Test - public void testInitBookieNoWritableDirsButHasEnoughSpaces() throws Exception { - float usage = 1.0f - ((float) ledgerDir.getUsableSpace()) / ledgerDir.getTotalSpace(); - conf.setDiskUsageThreshold(usage / 2); - conf.setDiskUsageWarnThreshold(usage / 3); - conf.setMinUsableSizeForEntryLogCreation(Long.MIN_VALUE); - conf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - - bookie = new TestBookieImpl(conf); - bookie.start(); - - CompletableFuture writeFuture = new CompletableFuture<>(); - bookie.addEntry( - generateEntry(1L, 2L), - false, - (rc, ledgerId, entryId, addr, ctx) -> writeFuture.complete(rc), - null, - new byte[0] - ); - assertEquals(Code.OK, writeFuture.get().intValue()); - } - - @Test - public void testInitBookieNoWritableDirsAndNoEnoughSpaces() throws Exception { - float usage = 1.0f - ((float) ledgerDir.getUsableSpace()) / ledgerDir.getTotalSpace(); - conf.setDiskUsageThreshold(usage / 2); - conf.setDiskUsageWarnThreshold(usage / 3); - conf.setMinUsableSizeForEntryLogCreation(Long.MAX_VALUE); - conf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - - bookie = new TestBookieImpl(conf); - bookie.start(); - - try { - bookie.addEntry( - generateEntry(1L, 2L), - false, - (rc, ledgerId, entryId, addr, ctx) -> {}, - null, - new byte[0] - ); - fail("Should fail on creating new entry log file" - + " since there is no enough disk space to accommodate writes"); - } catch (IOException ioe) { - // expected - assertTrue(ioe.getCause() instanceof NoWritableLedgerDirException); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SkipListArenaTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SkipListArenaTest.java deleted file mode 100644 index f972c3ef19a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SkipListArenaTest.java +++ /dev/null @@ -1,206 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.primitives.Ints; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.bookie.SkipListArena.MemorySlice; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.junit.Test; - -/** - * Test the SkipListArena class. - */ -public class SkipListArenaTest { - - class CustomConfiguration extends ServerConfiguration { - @Override - public int getSkipListArenaChunkSize() { - return 4096; - } - @Override - public int getSkipListArenaMaxAllocSize() { - return 1024; - } - @Override - public boolean getJournalFlushWhenQueueEmpty() { - return true; - } - - } - - final CustomConfiguration cfg = new CustomConfiguration(); - - /** - * Test random allocations. - */ - @Test - public void testRandomAllocation() { - Random rand = new Random(); - SkipListArena arena = new SkipListArena(cfg); - int expectedOff = 0; - byte[] lastBuffer = null; - - // 10K iterations by 0-512 alloc -> 2560kB expected - // should be reasonable for unit test and also cover wraparound - // behavior - for (int i = 0; i < 10000; i++) { - int size = rand.nextInt(512); - MemorySlice alloc = arena.allocateBytes(size); - - if (alloc.getData() != lastBuffer) { - expectedOff = 0; - lastBuffer = alloc.getData(); - } - assertTrue(expectedOff == alloc.getOffset()); - assertTrue("Allocation " + alloc + " overruns buffer", - alloc.getOffset() + size <= alloc.getData().length); - expectedOff += size; - } - } - - @Test - public void testLargeAllocation() { - SkipListArena arena = new SkipListArena(cfg); - MemorySlice alloc = arena.allocateBytes(1024 + 1024); - assertNull("2KB allocation shouldn't be satisfied by LAB.", alloc); - } - - private class ByteArray { - final byte[] bytes; - ByteArray(final byte[] bytes) { - this.bytes = bytes; - } - - @Override - public int hashCode() { - return bytes.hashCode(); - } - - @Override - public boolean equals(Object object) { - if (object instanceof ByteArray) { - ByteArray other = (ByteArray) object; - return this.bytes.equals(other.bytes); - } - return false; - } - } - - private static class AllocBuffer implements Comparable{ - private final MemorySlice alloc; - private final int size; - public AllocBuffer(MemorySlice alloc, int size) { - super(); - this.alloc = alloc; - this.size = size; - } - - @Override - public int compareTo(AllocBuffer e) { - assertTrue(alloc.getData() == e.alloc.getData()); - return Ints.compare(alloc.getOffset(), e.alloc.getOffset()); - } - - @Override - public String toString() { - return alloc + ":" + size; - } - } - - private Thread getAllocThread(final ConcurrentLinkedQueue queue, - final CountDownLatch latch, - final SkipListArena arena) { - return new Thread(new Runnable() { - @Override - public void run() { - Random rand = new Random(); - for (int j = 0; j < 1000; j++) { - int size = rand.nextInt(512); - MemorySlice alloc = arena.allocateBytes(size); - queue.add(new AllocBuffer(alloc, size)); - } - latch.countDown(); - } - }); - } - - /** - * Test concurrent allocation, check the results don't overlap. - */ - @Test - public void testConcurrency() throws Exception { - final SkipListArena arena = new SkipListArena(cfg); - final CountDownLatch latch = new CountDownLatch(10); - final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); - - Set testThreads = new HashSet(); - for (int i = 0; i < 10; i++) { - testThreads.add(getAllocThread(queue, latch, arena)); - } - - for (Thread thread : testThreads) { - thread.start(); - } - latch.await(); - - // Partition the allocations by the actual byte[] they share, - // make sure offsets are unique and non-overlap for each buffer. - Map> mapsByArray = new HashMap>(); - boolean overlapped = false; - - final AllocBuffer[] buffers = queue.toArray(new AllocBuffer[0]); - for (AllocBuffer buf : buffers) { - if (buf.size != 0) { - ByteArray ptr = new ByteArray(buf.alloc.getData()); - Map treeMap = mapsByArray.get(ptr); - if (treeMap == null) { - treeMap = new TreeMap(); - mapsByArray.put(ptr, treeMap); - } - AllocBuffer other = treeMap.put(buf.alloc.getOffset(), buf); - if (other != null) { - fail("Buffer " + other + " overlapped with " + buf); - } - } - } - - // Now check each byte array to make sure allocations don't overlap - for (Map treeMap : mapsByArray.values()) { - int expectedOff = 0; - for (AllocBuffer buf : treeMap.values()) { - assertEquals(expectedOff, buf.alloc.getOffset()); - expectedOff += buf.size; - } - } - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowInterleavedLedgerStorage.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowInterleavedLedgerStorage.java deleted file mode 100644 index a4061b574f2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowInterleavedLedgerStorage.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.apache.bookkeeper.bookie; - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.IOException; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.stats.StatsLogger; - -/** - * Strictly for testing. - * have to be in org.apache.bookkeeper.bookie to not introduce changes to InterleavedLedgerStorage - */ -public class SlowInterleavedLedgerStorage extends InterleavedLedgerStorage { - - public static final String PROP_SLOW_STORAGE_FLUSH_DELAY = "test.slowStorage.flushDelay"; - public static final String PROP_SLOW_STORAGE_ADD_DELAY = "test.slowStorage.addDelay"; - public static final String PROP_SLOW_STORAGE_GET_DELAY = "test.slowStorage.getDelay"; - - /** - * Strictly for testing. - */ - public static class SlowDefaultEntryLogger extends DefaultEntryLogger { - public volatile long getDelay = 0; - public volatile long addDelay = 0; - public volatile long flushDelay = 0; - - public SlowDefaultEntryLogger(ServerConfiguration conf, - LedgerDirsManager ledgerDirsManager, - EntryLogListener listener, - StatsLogger statsLogger) throws IOException { - super(conf, ledgerDirsManager, listener, statsLogger, UnpooledByteBufAllocator.DEFAULT); - } - - public SlowDefaultEntryLogger setAddDelay(long delay) { - addDelay = delay; - return this; - } - - public SlowDefaultEntryLogger setGetDelay(long delay) { - getDelay = delay; - return this; - } - - public SlowDefaultEntryLogger setFlushDelay(long delay) { - flushDelay = delay; - return this; - } - - @Override - public void flush() throws IOException { - delayMs(flushDelay); - super.flush(); - } - - @Override - public long addEntry(long ledger, ByteBuf entry) throws IOException { - delayMs(addDelay); - return super.addEntry(ledger, entry); - } - - @Override - public ByteBuf readEntry(long ledgerId, long entryId, long location) - throws IOException, Bookie.NoEntryException { - delayMs(getDelay); - return super.readEntry(ledgerId, entryId, location); - } - - private static void delayMs(long delay) { - if (delay < 1) { - return; - } - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - //noop - } - } - - } - - public SlowInterleavedLedgerStorage() { - super(); - } - - @Override - public void initialize(ServerConfiguration conf, - LedgerManager ledgerManager, - LedgerDirsManager ledgerDirsManager, - LedgerDirsManager indexDirsManager, - StatsLogger statsLogger, - ByteBufAllocator allocator) - throws IOException { - super.initialize(conf, ledgerManager, ledgerDirsManager, indexDirsManager, - statsLogger, allocator); - // do not want to add these to config class, reading throw "raw" interface - long getDelay = conf.getLong(PROP_SLOW_STORAGE_GET_DELAY, 0); - long addDelay = conf.getLong(PROP_SLOW_STORAGE_ADD_DELAY, 0); - long flushDelay = conf.getLong(PROP_SLOW_STORAGE_FLUSH_DELAY, 0); - - entryLogger = new SlowDefaultEntryLogger(conf, ledgerDirsManager, this, statsLogger) - .setAddDelay(addDelay) - .setGetDelay(getDelay) - .setFlushDelay(flushDelay); - } - - public void setAddDelay(long delay) { - ((SlowDefaultEntryLogger) entryLogger).setAddDelay(delay); - } - - public void setGetDelay(long delay) { - ((SlowDefaultEntryLogger) entryLogger).setGetDelay(delay); - } - - public void setFlushDelay(long delay) { - ((SlowDefaultEntryLogger) entryLogger).setFlushDelay(delay); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowSortedLedgerStorage.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowSortedLedgerStorage.java deleted file mode 100644 index e12976d04e3..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowSortedLedgerStorage.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.apache.bookkeeper.bookie; - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -/** - * Strictly for unit testing. - */ -public class SlowSortedLedgerStorage extends SortedLedgerStorage { - - public SlowSortedLedgerStorage() { - this(new SlowInterleavedLedgerStorage()); - } - - SlowSortedLedgerStorage(InterleavedLedgerStorage ils) { - super(ils); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageCheckpointTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageCheckpointTest.java deleted file mode 100644 index 42cdb943eee..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageCheckpointTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.RequiredArgsConstructor; -import lombok.ToString; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Test {@link SortedLedgerStorage}. - */ -@Slf4j -public class SortedLedgerStorageCheckpointTest extends LedgerStorageTestBase { - - @Data - @RequiredArgsConstructor - @ToString - @EqualsAndHashCode - private static class TestCheckpoint implements Checkpoint { - - private final long offset; - - @Override - public int compareTo(Checkpoint o) { - if (Checkpoint.MAX == o) { - return -1; - } - - TestCheckpoint other = (TestCheckpoint) o; - return Long.compare(offset, other.offset); - } - - } - - @RequiredArgsConstructor - private static class TestCheckpointSource implements CheckpointSource { - - private long currentOffset = 0; - - void advanceOffset(long numBytes) { - currentOffset += numBytes; - } - - @Override - public Checkpoint newCheckpoint() { - TestCheckpoint cp = new TestCheckpoint(currentOffset); - log.info("New checkpoint : {}", cp); - return cp; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) - throws IOException { - log.info("Complete checkpoint : {}", checkpoint); - } - } - - private SortedLedgerStorage storage; - private Checkpointer checkpointer; - private final LinkedBlockingQueue checkpoints; - private final TestCheckpointSource checkpointSrc = new TestCheckpointSource(); - - public SortedLedgerStorageCheckpointTest() { - super(); - conf.setEntryLogSizeLimit(1024); - conf.setEntryLogFilePreAllocationEnabled(false); - this.checkpoints = new LinkedBlockingQueue<>(); - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - - // initial checkpoint - - this.storage = new SortedLedgerStorage(); - this.checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - storage.getScheduler().submit(() -> { - log.info("Checkpoint the storage at {}", checkpoint); - try { - storage.checkpoint(checkpoint); - checkpoints.add(checkpoint); - } catch (IOException e) { - log.error("Failed to checkpoint at {}", checkpoint, e); - } - }); - } - - @Override - public void start() { - // no-op - } - }; - - // if the SortedLedgerStorage need not to change bookie's state, pass StateManager==null is ok - this.storage.initialize( - conf, - mock(LedgerManager.class), - ledgerDirsManager, - ledgerDirsManager, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT); - this.storage.setCheckpointer(checkpointer); - this.storage.setCheckpointSource(checkpointSrc); - } - - @After - @Override - public void tearDown() throws Exception { - if (null != storage) { - storage.shutdown(); - } - super.tearDown(); - } - - ByteBuf prepareEntry(long ledgerId, long entryId) { - ByteBuf entry = Unpooled.buffer(4 * Long.BYTES); - // ledger id, entry id, lac - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeLong(entryId - 1); - // data - entry.writeLong(entryId); - return entry; - } - - @Test - public void testCheckpoint() throws Exception { - // memory table holds the first checkpoint, but it is not completed yet. - Checkpoint memtableCp = storage.memTable.kvmap.cp; - assertEquals(new TestCheckpoint(0), memtableCp); - - // write entries into ledger storage - long lid = System.currentTimeMillis(); - storage.setMasterKey(lid, new byte[0]); - for (int i = 0; i < 20; i++) { - storage.addEntry(prepareEntry(lid, i)); - } - // simulate journal persists the entries in journal; - checkpointSrc.advanceOffset(100); - - // memory table holds the first checkpoint, but it is not completed yet. - memtableCp = storage.memTable.kvmap.cp; - assertEquals(new TestCheckpoint(0), memtableCp); - - // trigger a memtable flush - Assert.assertNotNull("snapshot shouldn't have returned null", storage.memTable.snapshot()); - storage.onSizeLimitReached(checkpointSrc.newCheckpoint()); - // wait for checkpoint to complete - checkpoints.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - assertEquals(new TestCheckpoint(100), storage.memTable.kvmap.cp); - assertEquals(0, storage.memTable.kvmap.size()); - } - - @Test - public void testCheckpointAfterEntryLogRotated() throws Exception { - // memory table holds the first checkpoint, but it is not completed yet. - Checkpoint memtableCp = storage.memTable.kvmap.cp; - assertEquals(new TestCheckpoint(0), memtableCp); - - // write entries into ledger storage - long lid = System.currentTimeMillis(); - storage.setMasterKey(lid, new byte[0]); - for (int i = 0; i < 20; i++) { - storage.addEntry(prepareEntry(lid, i)); - } - // simulate journal persists the entries in journal; - checkpointSrc.advanceOffset(100); - - // memory table holds the first checkpoint, but it is not completed yet. - memtableCp = storage.memTable.kvmap.cp; - assertEquals(new TestCheckpoint(0), memtableCp); - assertEquals(20, storage.memTable.kvmap.size()); - - final CountDownLatch readyLatch = new CountDownLatch(1); - storage.getScheduler().submit(() -> { - try { - readyLatch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - }); - - // simulate entry log is rotated (due to compaction) - DefaultEntryLogger elogger = storage.getEntryLogger(); - EntryLogManagerForSingleEntryLog entryLogManager = - (EntryLogManagerForSingleEntryLog) elogger.getEntryLogManager(); - entryLogManager.createNewLog(DefaultEntryLogger.UNASSIGNED_LEDGERID); - long currentLogId = entryLogManager.getCurrentLogId(); - - readyLatch.countDown(); - assertNull(checkpoints.poll()); - assertEquals(new TestCheckpoint(0), storage.memTable.kvmap.cp); - assertEquals(20, storage.memTable.kvmap.size()); - - // trigger a memtable flush - Assert.assertNotNull("snapshot shouldn't have returned null", storage.memTable.snapshot()); - storage.onSizeLimitReached(checkpointSrc.newCheckpoint()); - assertEquals(new TestCheckpoint(100), checkpoints.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS)); - - // all the entries are flushed out - assertEquals(new TestCheckpoint(100), storage.memTable.kvmap.cp); - assertEquals(0, storage.memTable.kvmap.size()); - assertTrue( - "current log " + currentLogId + " contains entries added from memtable should be forced to disk" - + " but flushed logs are " + elogger.getFlushedLogIds(), - elogger.getFlushedLogIds().contains(currentLogId)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageTest.java deleted file mode 100644 index db83f096d95..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageTest.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.BOOKIE_SCOPE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.PrimitiveIterator.OfLong; -import java.util.function.Consumer; -import java.util.stream.IntStream; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.DiskChecker; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -/** - * Testing SortedLedgerStorage. - */ -@RunWith(Parameterized.class) -public class SortedLedgerStorageTest { - - TestStatsProvider statsProvider = new TestStatsProvider(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - LedgerDirsManager ledgerDirsManager; - SortedLedgerStorage sortedLedgerStorage = new SortedLedgerStorage(); - - final long numWrites = 2000; - final long moreNumOfWrites = 3000; - final long entriesPerWrite = 2; - final long numOfLedgers = 5; - - @Parameterized.Parameters - public static Iterable elplSetting() { - return Arrays.asList(true, false); - } - - public SortedLedgerStorageTest(boolean elplSetting) { - conf.setEntryLogSizeLimit(2048); - conf.setEntryLogPerLedgerEnabled(elplSetting); - } - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - @Before - public void setUp() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - sortedLedgerStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - statsProvider.getStatsLogger(BOOKIE_SCOPE), UnpooledByteBufAllocator.DEFAULT); - sortedLedgerStorage.setCheckpointSource(checkpointSource); - sortedLedgerStorage.setCheckpointer(checkpointer); - } - - @Test - public void testGetListOfEntriesOfLedger() throws Exception { - long nonExistingLedgerId = 123456L; - OfLong entriesItr = sortedLedgerStorage.getListOfEntriesOfLedger(nonExistingLedgerId); - assertFalse("There shouldn't be any entries for this ledger", entriesItr.hasNext()); - // Insert some ledger & entries in the interleaved storage - for (long entryId = 0; entryId < numWrites; entryId++) { - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - if (entryId == 0) { - sortedLedgerStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - sortedLedgerStorage.setFenced(ledgerId); - } - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId * entriesPerWrite); - entry.writeBytes(("entry-" + entryId).getBytes()); - - sortedLedgerStorage.addEntry(entry); - } - } - - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - OfLong entriesOfLedger = sortedLedgerStorage.getListOfEntriesOfLedger(ledgerId); - ArrayList arrayList = new ArrayList(); - Consumer addMethod = arrayList::add; - entriesOfLedger.forEachRemaining(addMethod); - assertEquals("Number of entries", numWrites, arrayList.size()); - assertTrue("Entries of Ledger", IntStream.range(0, arrayList.size()).allMatch(i -> { - return arrayList.get(i) == (i * entriesPerWrite); - })); - } - - nonExistingLedgerId = 456789L; - entriesItr = sortedLedgerStorage.getListOfEntriesOfLedger(nonExistingLedgerId); - assertFalse("There shouldn't be any entry", entriesItr.hasNext()); - } - - @Test - public void testGetListOfEntriesOfLedgerAfterFlush() throws IOException { - // Insert some ledger & entries in the interleaved storage - for (long entryId = 0; entryId < numWrites; entryId++) { - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - if (entryId == 0) { - sortedLedgerStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - sortedLedgerStorage.setFenced(ledgerId); - } - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId * entriesPerWrite); - entry.writeBytes(("entry-" + entryId).getBytes()); - - sortedLedgerStorage.addEntry(entry); - } - } - - sortedLedgerStorage.flush(); - - // Insert some more ledger & entries in the interleaved storage - for (long entryId = numWrites; entryId < moreNumOfWrites; entryId++) { - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId * entriesPerWrite); - entry.writeBytes(("entry-" + entryId).getBytes()); - - sortedLedgerStorage.addEntry(entry); - } - } - - for (long ledgerId = 0; ledgerId < numOfLedgers; ledgerId++) { - OfLong entriesOfLedger = sortedLedgerStorage.getListOfEntriesOfLedger(ledgerId); - ArrayList arrayList = new ArrayList(); - Consumer addMethod = arrayList::add; - entriesOfLedger.forEachRemaining(addMethod); - assertEquals("Number of entries", moreNumOfWrites, arrayList.size()); - assertTrue("Entries of Ledger", IntStream.range(0, arrayList.size()).allMatch(i -> { - return arrayList.get(i) == (i * entriesPerWrite); - })); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/StateManagerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/StateManagerTest.java deleted file mode 100644 index 2f3c71c1764..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/StateManagerTest.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.zk.ZKMetadataBookieDriver; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Testing StateManager cases. - */ -public class StateManagerTest extends BookKeeperClusterTestCase { - - @Rule - public final TestName runtime = new TestName(); - final ServerConfiguration conf; - MetadataBookieDriver driver; - - public StateManagerTest(){ - super(0); - String ledgersPath = "/" + "ledgers" + runtime.getMethodName(); - baseClientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri(ledgersPath)); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri(ledgersPath)); - conf = TestBKConfiguration.newServerConfiguration(); - driver = new ZKMetadataBookieDriver(); - - } - - @Override - public void setUp() throws Exception { - super.setUp(); - zkUtil.createBKEnsemble("/" + runtime.getMethodName()); - File tmpDir = tmpDirs.createNew("stateManger", "test"); - conf.setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setJournalDirName(tmpDir.toString()) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - if (driver != null) { - driver.close(); - } - } - - /** - * StateManager can transition between writable mode and readOnly mode if it was not created with readOnly mode. - */ - @Test - public void testNormalBookieTransitions() throws Exception { - driver.initialize(conf, NullStatsLogger.INSTANCE); - try (RegistrationManager rm = driver.createRegistrationManager(); - BookieStateManager stateManager = new BookieStateManager(conf, rm)) { - rm.addRegistrationListener(() -> { - stateManager.forceToUnregistered(); - // schedule a re-register operation - stateManager.registerBookie(false); - }); - stateManager.initState(); - stateManager.registerBookie(true).get(); - - assertTrue(stateManager.isRunning()); - assertTrue(stateManager.isRegistered()); - - stateManager.transitionToReadOnlyMode().get(); - assertTrue(stateManager.isReadOnly()); - - stateManager.transitionToWritableMode().get(); - assertTrue(stateManager.isRunning()); - assertFalse(stateManager.isReadOnly()); - stateManager.close(); - assertFalse(stateManager.isRunning()); - } - } - - @Test - public void testReadOnlyDisableBookieTransitions() throws Exception { - conf.setReadOnlyModeEnabled(false); - // readOnly disabled bk stateManager - driver.initialize( - conf, - NullStatsLogger.INSTANCE); - - RegistrationManager rm = driver.createRegistrationManager(); - BookieStateManager stateManager = new BookieStateManager(conf, rm); - // simulate sync shutdown logic in bookie - stateManager.setShutdownHandler(new StateManager.ShutdownHandler() { - @Override - public void shutdown(int code) { - try { - if (stateManager.isRunning()) { - stateManager.forceToShuttingDown(); - stateManager.forceToReadOnly(); - } - - } finally { - stateManager.close(); - } - } - }); - rm.addRegistrationListener(() -> { - stateManager.forceToUnregistered(); - // schedule a re-register operation - stateManager.registerBookie(false); - }); - - stateManager.initState(); - stateManager.registerBookie(true).get(); - assertTrue(stateManager.isRunning()); - - stateManager.transitionToReadOnlyMode().get(); - // stateManager2 will shutdown - assertFalse(stateManager.isRunning()); - // different dimension of bookie state: running <--> down, read <--> write, unregistered <--> registered - // bookie2 is set to readOnly when shutdown - assertTrue(stateManager.isReadOnly()); - } - - @Test - public void testReadOnlyBookieTransitions() throws Exception{ - // readOnlybk, which use override stateManager impl - File tmpDir = tmpDirs.createNew("stateManger", "test-readonly"); - final ServerConfiguration readOnlyConf = TestBKConfiguration.newServerConfiguration(); - readOnlyConf.setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setJournalDirName(tmpDir.toString()) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setForceReadOnlyBookie(true); - driver.initialize(readOnlyConf, NullStatsLogger.INSTANCE); - - ReadOnlyBookie readOnlyBookie = TestBookieImpl.buildReadOnly( - new TestBookieImpl.ResourceBuilder(readOnlyConf) - .withMetadataDriver(driver).build()); - readOnlyBookie.start(); - assertTrue(readOnlyBookie.isRunning()); - assertTrue(readOnlyBookie.isReadOnly()); - - // transition has no effect if bookie start with readOnly mode - readOnlyBookie.getStateManager().transitionToWritableMode().get(); - assertTrue(readOnlyBookie.isRunning()); - assertTrue(readOnlyBookie.isReadOnly()); - readOnlyBookie.shutdown(); - - } - - /** - * Verify the bookie reg. - */ - @Test - public void testRegistration() throws Exception { - driver.initialize( - conf, - NullStatsLogger.INSTANCE); - - RegistrationManager rm = driver.createRegistrationManager(); - BookieStateManager stateManager = new BookieStateManager(conf, rm); - rm.addRegistrationListener(() -> { - stateManager.forceToUnregistered(); - // schedule a re-register operation - stateManager.registerBookie(false); - }); - - // simulate sync shutdown logic in bookie - stateManager.setShutdownHandler(new StateManager.ShutdownHandler() { - @Override - public void shutdown(int code) { - try { - if (stateManager.isRunning()) { - stateManager.forceToShuttingDown(); - stateManager.forceToReadOnly(); - } - - } finally { - stateManager.close(); - } - } - }); - stateManager.initState(); - // up - assertTrue(stateManager.isRunning()); - // unregistered - assertFalse(stateManager.isRegistered()); - - stateManager.registerBookie(true).get(); - // registered - assertTrue(stateManager.isRegistered()); - stateManager.getShutdownHandler().shutdown(ExitCode.OK); - // readOnly - assertTrue(stateManager.isReadOnly()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SyncThreadTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SyncThreadTest.java deleted file mode 100644 index 6df1bacb80d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SyncThreadTest.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.io.IOException; -import java.util.EnumSet; -import java.util.PrimitiveIterator.OfLong; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.LedgerDirsManager.LedgerDirsListener; -import org.apache.bookkeeper.bookie.LedgerDirsManager.NoWritableLedgerDirException; -import org.apache.bookkeeper.common.util.Watcher; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test a synchronization thread. - */ -public class SyncThreadTest { - private static final Logger LOG = LoggerFactory.getLogger(SyncThreadTest.class); - - ExecutorService executor = null; - - @Before - public void setupExecutor() { - executor = Executors.newSingleThreadExecutor(); - } - - @After - public void teardownExecutor() { - if (executor != null) { - executor.shutdownNow(); - executor = null; - } - } - - /** - * Test that if a flush is taking a long time, - * the sync thread will not shutdown until it - * has finished. - */ - @Test - public void testSyncThreadLongShutdown() throws Exception { - int flushInterval = 100; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setFlushInterval(flushInterval); - CheckpointSource checkpointSource = new DummyCheckpointSource(); - LedgerDirsListener listener = new LedgerDirsListener() {}; - - final CountDownLatch checkpointCalledLatch = new CountDownLatch(1); - final CountDownLatch checkpointLatch = new CountDownLatch(1); - - final CountDownLatch flushCalledLatch = new CountDownLatch(1); - final CountDownLatch flushLatch = new CountDownLatch(1); - final AtomicBoolean failedSomewhere = new AtomicBoolean(false); - LedgerStorage storage = new DummyLedgerStorage() { - @Override - public void flush() throws IOException { - flushCalledLatch.countDown(); - try { - flushLatch.await(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - LOG.error("Interrupted in flush thread", ie); - failedSomewhere.set(true); - } - } - - @Override - public void checkpoint(Checkpoint checkpoint) - throws IOException { - checkpointCalledLatch.countDown(); - try { - checkpointLatch.await(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - LOG.error("Interrupted in checkpoint thread", ie); - failedSomewhere.set(true); - } - } - }; - - final SyncThread t = new SyncThread(conf, listener, storage, checkpointSource, NullStatsLogger.INSTANCE); - t.startCheckpoint(Checkpoint.MAX); - assertTrue("Checkpoint should have been called", - checkpointCalledLatch.await(10, TimeUnit.SECONDS)); - Future done = executor.submit(() -> { - try { - t.shutdown(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - LOG.error("Interrupted shutting down sync thread", ie); - failedSomewhere.set(true); - return false; - } - return true; - }); - checkpointLatch.countDown(); - assertFalse("Shutdown shouldn't have finished", done.isDone()); - assertTrue("Flush should have been called", - flushCalledLatch.await(10, TimeUnit.SECONDS)); - - assertFalse("Shutdown shouldn't have finished", done.isDone()); - flushLatch.countDown(); - - assertTrue("Shutdown should have finished successfully", done.get(10, TimeUnit.SECONDS)); - assertFalse("Shouldn't have failed anywhere", failedSomewhere.get()); - } - - /** - * Test that sync thread suspension works. - * i.e. when we suspend the syncthread, nothing - * will be synced. - */ - @Test - public void testSyncThreadSuspension() throws Exception { - int flushInterval = 100; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setFlushInterval(flushInterval); - CheckpointSource checkpointSource = new DummyCheckpointSource(); - LedgerDirsListener listener = new LedgerDirsListener() {}; - - final AtomicInteger checkpointCount = new AtomicInteger(0); - LedgerStorage storage = new DummyLedgerStorage() { - @Override - public void checkpoint(Checkpoint checkpoint) - throws IOException { - checkpointCount.incrementAndGet(); - } - }; - final SyncThread t = new SyncThread(conf, listener, storage, checkpointSource, NullStatsLogger.INSTANCE); - t.startCheckpoint(Checkpoint.MAX); - while (checkpointCount.get() == 0) { - Thread.sleep(flushInterval); - } - t.suspendSync(); - Thread.sleep(flushInterval); - int count = checkpointCount.get(); - for (int i = 0; i < 10; i++) { - t.startCheckpoint(Checkpoint.MAX); - assertEquals("Checkpoint count shouldn't change", count, checkpointCount.get()); - } - t.resumeSync(); - int i = 0; - while (checkpointCount.get() == count) { - Thread.sleep(flushInterval); - i++; - if (i > 100) { - fail("Checkpointing never resumed"); - } - } - t.shutdown(); - } - - /** - * Test that if the ledger storage throws a - * runtime exception, the bookie will be told - * to shutdown. - */ - @Test - public void testSyncThreadShutdownOnError() throws Exception { - int flushInterval = 100; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setFlushInterval(flushInterval); - CheckpointSource checkpointSource = new DummyCheckpointSource(); - final CountDownLatch fatalLatch = new CountDownLatch(1); - LedgerDirsListener listener = new LedgerDirsListener() { - @Override - public void fatalError() { - fatalLatch.countDown(); - } - }; - - LedgerStorage storage = new DummyLedgerStorage() { - @Override - public void checkpoint(Checkpoint checkpoint) - throws IOException { - throw new RuntimeException("Fatal error in sync thread"); - } - }; - final SyncThread t = new SyncThread(conf, listener, storage, checkpointSource, NullStatsLogger.INSTANCE); - t.startCheckpoint(Checkpoint.MAX); - assertTrue("Should have called fatal error", fatalLatch.await(10, TimeUnit.SECONDS)); - t.shutdown(); - } - - /** - * Test that if the ledger storage throws - * a disk full exception, the owner of the sync - * thread will be notified. - */ - @Test - public void testSyncThreadDisksFull() throws Exception { - int flushInterval = 100; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setFlushInterval(flushInterval); - CheckpointSource checkpointSource = new DummyCheckpointSource(); - final CountDownLatch diskFullLatch = new CountDownLatch(1); - LedgerDirsListener listener = new LedgerDirsListener() { - @Override - public void allDisksFull(boolean highPriorityWritesAllowed) { - diskFullLatch.countDown(); - } - }; - - LedgerStorage storage = new DummyLedgerStorage() { - @Override - public void checkpoint(Checkpoint checkpoint) - throws IOException { - throw new NoWritableLedgerDirException("Disk full error in sync thread"); - } - }; - final SyncThread t = new SyncThread(conf, listener, storage, checkpointSource, NullStatsLogger.INSTANCE); - t.startCheckpoint(Checkpoint.MAX); - assertTrue("Should have disk full error", diskFullLatch.await(10, TimeUnit.SECONDS)); - t.shutdown(); - } - - private static class DummyCheckpointSource implements CheckpointSource { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) - throws IOException { - } - } - - private static class DummyLedgerStorage implements LedgerStorage { - @Override - public void initialize( - ServerConfiguration conf, - LedgerManager ledgerManager, - LedgerDirsManager ledgerDirsManager, - LedgerDirsManager indexDirsManager, - StatsLogger statsLogger, - ByteBufAllocator allocator) - throws IOException { - } - @Override - public void setStateManager(StateManager stateManager) {} - @Override - public void setCheckpointSource(CheckpointSource checkpointSource) {} - @Override - public void setCheckpointer(Checkpointer checkpointer) {} - - @Override - public void deleteLedger(long ledgerId) throws IOException { - } - - @Override - public void start() { - } - - @Override - public void shutdown() throws InterruptedException { - } - - @Override - public boolean ledgerExists(long ledgerId) throws IOException { - return true; - } - - @Override - public boolean entryExists(long ledgerId, long entryId) throws IOException { - return false; - } - - @Override - public boolean setFenced(long ledgerId) throws IOException { - return true; - } - - @Override - public boolean isFenced(long ledgerId) throws IOException { - return false; - } - - @Override - public void setMasterKey(long ledgerId, byte[] masterKey) - throws IOException { - } - - @Override - public byte[] readMasterKey(long ledgerId) - throws IOException, BookieException { - return new byte[0]; - } - - @Override - public long addEntry(ByteBuf entry) throws IOException { - return 1L; - } - - @Override - public ByteBuf getEntry(long ledgerId, long entryId) - throws IOException { - return null; - } - - @Override - public long getLastAddConfirmed(long ledgerId) throws IOException { - return 0; - } - - @Override - public void flush() throws IOException { - } - - @Override - public void setExplicitLac(long ledgerId, ByteBuf lac) { - } - - @Override - public ByteBuf getExplicitLac(long ledgerId) { - return null; - } - - @Override - public boolean waitForLastAddConfirmedUpdate(long ledgerId, - long previousLAC, - Watcher watcher) - throws IOException { - return false; - } - - @Override - public void cancelWaitForLastAddConfirmedUpdate(long ledgerId, - Watcher watcher) - throws IOException { - } - - @Override - public void checkpoint(Checkpoint checkpoint) - throws IOException { - } - - @Override - public void registerLedgerDeletionListener(LedgerDeletionListener listener) { - } - - @Override - public OfLong getListOfEntriesOfLedger(long ledgerId) { - return null; - } - - @Override - public void setLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public boolean hasLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public void clearLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public EnumSet getStorageStateFlags() throws IOException { - return EnumSet.noneOf(StorageState.class); - } - - @Override - public void setStorageStateFlag(StorageState flag) throws IOException { - } - - @Override - public void clearStorageStateFlag(StorageState flag) throws IOException { - } - - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/TestBookieImpl.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/TestBookieImpl.java deleted file mode 100644 index cd0e967b61c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/TestBookieImpl.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import io.netty.buffer.UnpooledByteBufAllocator; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.NullMetadataBookieDriver; -import org.apache.bookkeeper.proto.SimpleBookieServiceInfoProvider; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.util.DiskChecker; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test wrapper for BookieImpl that chooses defaults for dependencies. - */ -public class TestBookieImpl extends BookieImpl { - private static final Logger log = LoggerFactory.getLogger(TestBookieImpl.class); - - private final Resources resources; - - public TestBookieImpl(ServerConfiguration conf) throws Exception { - this(new ResourceBuilder(conf).build()); - } - - public TestBookieImpl(Resources resources, StatsLogger statsLogger) throws Exception { - super(resources.conf, - resources.registrationManager, - resources.storage, - resources.diskChecker, - resources.ledgerDirsManager, - resources.indexDirsManager, - statsLogger, - UnpooledByteBufAllocator.DEFAULT, - new SimpleBookieServiceInfoProvider(resources.conf)); - this.resources = resources; - } - - public TestBookieImpl(Resources resources) throws Exception { - super(resources.conf, - resources.registrationManager, - resources.storage, - resources.diskChecker, - resources.ledgerDirsManager, - resources.indexDirsManager, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT, - new SimpleBookieServiceInfoProvider(resources.conf)); - this.resources = resources; - } - - public static ReadOnlyBookie buildReadOnly(Resources resources) throws Exception { - return new ReadOnlyBookie(resources.conf, - resources.registrationManager, - resources.storage, - resources.diskChecker, - resources.ledgerDirsManager, - resources.indexDirsManager, - NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT, - new SimpleBookieServiceInfoProvider(resources.conf)); - } - - public static ReadOnlyBookie buildReadOnly(ServerConfiguration conf) throws Exception { - return buildReadOnly(new ResourceBuilder(conf).build()); - } - - @Override - int shutdown(int exitCode) { - int ret = super.shutdown(exitCode); - resources.cleanup(); - return ret; - } - - /** - * Manages bookie resources including their cleanup. - */ - public static class Resources { - private final ServerConfiguration conf; - private final MetadataBookieDriver metadataDriver; - private final RegistrationManager registrationManager; - private final LedgerManagerFactory ledgerManagerFactory; - private final LedgerManager ledgerManager; - private final LedgerStorage storage; - private final DiskChecker diskChecker; - private final LedgerDirsManager ledgerDirsManager; - private final LedgerDirsManager indexDirsManager; - - Resources(ServerConfiguration conf, - MetadataBookieDriver metadataDriver, - RegistrationManager registrationManager, - LedgerManagerFactory ledgerManagerFactory, - LedgerManager ledgerManager, - LedgerStorage storage, - DiskChecker diskChecker, - LedgerDirsManager ledgerDirsManager, - LedgerDirsManager indexDirsManager) { - this.conf = conf; - this.metadataDriver = metadataDriver; - this.registrationManager = registrationManager; - this.ledgerManagerFactory = ledgerManagerFactory; - this.ledgerManager = ledgerManager; - this.storage = storage; - this.diskChecker = diskChecker; - this.ledgerDirsManager = ledgerDirsManager; - this.indexDirsManager = indexDirsManager; - } - - void cleanup() { - try { - ledgerManager.close(); - } catch (Exception e) { - log.warn("Error shutting down ledger manager", e); - } - try { - ledgerManagerFactory.close(); - } catch (Exception e) { - log.warn("Error shutting down ledger manager factory", e); - } - registrationManager.close(); - try { - metadataDriver.close(); - } catch (Exception e) { - log.warn("Error shutting down metadata driver", e); - } - } - } - - /** - * Builder for resources. - */ - public static class ResourceBuilder { - private final ServerConfiguration conf; - private MetadataBookieDriver metadataBookieDriver; - private RegistrationManager registrationManager; - - public ResourceBuilder(ServerConfiguration conf) { - this.conf = conf; - } - - public ResourceBuilder withMetadataDriver(MetadataBookieDriver driver) { - this.metadataBookieDriver = driver; - return this; - } - - public ResourceBuilder withRegistrationManager(RegistrationManager registrationManager) { - this.registrationManager = registrationManager; - return this; - } - - public Resources build() throws Exception { - return build(NullStatsLogger.INSTANCE); - } - - public Resources build(StatsLogger statsLogger) throws Exception { - if (metadataBookieDriver == null) { - if (conf.getMetadataServiceUri() == null) { - metadataBookieDriver = new NullMetadataBookieDriver(); - } else { - metadataBookieDriver = BookieResources.createMetadataDriver(conf, statsLogger); - } - } - if (registrationManager == null) { - registrationManager = metadataBookieDriver.createRegistrationManager(); - } - LedgerManagerFactory ledgerManagerFactory = metadataBookieDriver.getLedgerManagerFactory(); - LedgerManager ledgerManager = ledgerManagerFactory.newLedgerManager(); - - DiskChecker diskChecker = BookieResources.createDiskChecker(conf); - LedgerDirsManager ledgerDirsManager = BookieResources.createLedgerDirsManager( - conf, diskChecker, statsLogger); - LedgerDirsManager indexDirsManager = BookieResources.createIndexDirsManager( - conf, diskChecker, statsLogger, ledgerDirsManager); - - LedgerStorage storage = BookieResources.createLedgerStorage( - conf, ledgerManager, ledgerDirsManager, indexDirsManager, - statsLogger, UnpooledByteBufAllocator.DEFAULT); - - return new Resources(conf, - metadataBookieDriver, - registrationManager, - ledgerManagerFactory, - ledgerManager, - storage, - diskChecker, - ledgerDirsManager, - indexDirsManager); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UncleanShutdownDetectionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UncleanShutdownDetectionTest.java deleted file mode 100644 index 3903ec75b45..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UncleanShutdownDetectionTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.util.DiskChecker; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Test the unclean shutdown implementation. - */ -public class UncleanShutdownDetectionTest { - - @Rule - public TemporaryFolder tempDir = new TemporaryFolder(); - - @Test - public void testRegisterStartWithoutRegisterShutdownEqualsUncleanShutdown() throws IOException { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager( - conf, conf.getLedgerDirs(), diskChecker); - - UncleanShutdownDetection uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - uncleanShutdownDetection.registerStartUp(); - - assertTrue(uncleanShutdownDetection.lastShutdownWasUnclean()); - } - - @Test - public void testRegisterStartWithRegisterShutdownEqualsCleanShutdown() throws IOException { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager( - conf, conf.getLedgerDirs(), diskChecker); - - UncleanShutdownDetection uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - uncleanShutdownDetection.registerStartUp(); - uncleanShutdownDetection.registerCleanShutdown(); - - assertFalse(uncleanShutdownDetection.lastShutdownWasUnclean()); - } - - @Test - public void testRegisterStartWithoutRegisterShutdownEqualsUncleanShutdownMultipleDirs() throws IOException { - File ledgerDir1 = tempDir.newFolder("l1"); - File ledgerDir2 = tempDir.newFolder("l2"); - File ledgerDir3 = tempDir.newFolder("l3"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setLedgerDirNames(new String[] {ledgerDir1.getAbsolutePath(), ledgerDir2.getAbsolutePath(), - ledgerDir3.getAbsolutePath()}); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager( - conf, conf.getLedgerDirs(), diskChecker); - - UncleanShutdownDetection uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - uncleanShutdownDetection.registerStartUp(); - - assertTrue(uncleanShutdownDetection.lastShutdownWasUnclean()); - } - - @Test - public void testRegisterStartWithRegisterShutdownEqualsCleanShutdownMultipleDirs() throws IOException { - File ledgerDir1 = tempDir.newFolder("l1"); - File ledgerDir2 = tempDir.newFolder("l2"); - File ledgerDir3 = tempDir.newFolder("l3"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setLedgerDirNames(new String[] {ledgerDir1.getAbsolutePath(), ledgerDir2.getAbsolutePath(), - ledgerDir3.getAbsolutePath()}); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager( - conf, conf.getLedgerDirs(), diskChecker); - - UncleanShutdownDetection uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - uncleanShutdownDetection.registerStartUp(); - uncleanShutdownDetection.registerCleanShutdown(); - - assertFalse(uncleanShutdownDetection.lastShutdownWasUnclean()); - } - - @Test - public void testRegisterStartWithPartialRegisterShutdownEqualsUncleanShutdownMultipleDirs() throws IOException { - File ledgerDir1 = tempDir.newFolder("l1"); - File ledgerDir2 = tempDir.newFolder("l2"); - File ledgerDir3 = tempDir.newFolder("l3"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setLedgerDirNames(new String[] {ledgerDir1.getAbsolutePath(), ledgerDir2.getAbsolutePath(), - ledgerDir3.getAbsolutePath()}); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager( - conf, conf.getLedgerDirs(), diskChecker); - - UncleanShutdownDetection uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - uncleanShutdownDetection.registerStartUp(); - uncleanShutdownDetection.registerCleanShutdown(); - File dirtyFile = new File(ledgerDirsManager.getAllLedgerDirs().get(0), - UncleanShutdownDetectionImpl.DIRTY_FILENAME); - dirtyFile.createNewFile(); - - assertTrue(uncleanShutdownDetection.lastShutdownWasUnclean()); - } - - @Test(expected = IOException.class) - public void testRegisterStartFailsToCreateDirtyFilesAndThrowsIOException() throws IOException { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new MockLedgerDirsManager(conf, conf.getLedgerDirs(), diskChecker); - - UncleanShutdownDetection uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - uncleanShutdownDetection.registerStartUp(); - } - - private class MockLedgerDirsManager extends LedgerDirsManager { - public MockLedgerDirsManager(ServerConfiguration conf, File[] dirs, DiskChecker diskChecker) - throws IOException { - super(conf, dirs, diskChecker); - } - - @Override - public List getAllLedgerDirs() { - List dirs = new ArrayList<>(); - dirs.add(new File("does_not_exist")); - return dirs; - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpdateCookieCmdTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpdateCookieCmdTest.java deleted file mode 100644 index 51671140d9f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpdateCookieCmdTest.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie; - -import static org.apache.bookkeeper.util.BookKeeperConstants.COOKIE_NODE; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.UnknownHostException; -import java.util.List; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.server.Main; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.versioning.Version; -import org.apache.zookeeper.KeeperException; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This tests 'updatecookie' shell command. - */ -public class UpdateCookieCmdTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(UpdateCookieCmdTest.class); - - MetadataBookieDriver driver; - RegistrationManager rm; - ServerConfiguration conf; - - public UpdateCookieCmdTest() { - super(0); - useUUIDasBookieId = false; - } - - @Override - public void setUp() throws Exception { - super.setUp(); - LOG.info("setUp ZKRegistrationManager"); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - driver = MetadataDrivers.getBookieDriver( - URI.create(baseConf.getMetadataServiceUri())); - driver.initialize(baseConf, NullStatsLogger.INSTANCE); - rm = driver.createRegistrationManager(); - - conf = newServerConfiguration(); - LegacyCookieValidation validation = new LegacyCookieValidation(conf, rm); - validation.checkCookies(Main.storageDirectoriesFromConf(conf)); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - if (rm != null) { - rm.close(); - } - if (driver != null) { - driver.close(); - } - } - - /** - * updatecookie to hostname. - */ - @Test - public void testUpdateCookieIpAddressToHostname() throws Exception { - updateCookie("-bookieId", "hostname", true); - } - - /** - * updatecookie to short hostname. - */ - @Test - public void testUpdateCookieIpAddressToShortHostname() throws Exception { - updateCookie("-bookieId", "hostname", true, true); - } - - /** - * updatecookie to ipaddress. - */ - @Test - public void testUpdateCookieHostnameToIpAddress() throws Exception { - updateCookie("-bookieId", "hostname", true); - - updateCookie("-b", "ip", false); - - // start bookie to ensure everything works fine - conf.setUseHostNameAsBookieID(false); - LegacyCookieValidation validation = new LegacyCookieValidation(conf, rm); - validation.checkCookies(Main.storageDirectoriesFromConf(conf)); - } - - /** - * updatecookie to invalid bookie id. - */ - @Test - public void testUpdateCookieWithInvalidOption() throws Exception { - String[] argv = new String[] { "updatecookie", "-b", "invalidBookieID" }; - final ServerConfiguration conf = this.conf; - updateCookie(argv, -1, conf); - - argv = new String[] { "updatecookie", "-b" }; - updateCookie(argv, -1, conf); - - argv = new String[] { "updatecookie" }; - updateCookie(argv, -1, conf); - - // conf not updated - argv = new String[] { "updatecookie", "-b", "hostname" }; - conf.setUseHostNameAsBookieID(false); - updateCookie(argv, -1, conf); - - argv = new String[] { "updatecookie", "-b", "ip" }; - conf.setUseHostNameAsBookieID(true); - updateCookie(argv, -1, conf); - } - - /** - * During first updatecookie it successfully created the hostname cookie but - * it fails to delete the old ipaddress cookie. Here user will issue - * updatecookie again, now it should be able to delete the old cookie - * gracefully. - */ - @Test - public void testWhenBothIPaddressAndHostNameCookiesExists() throws Exception { - updateCookie("-b", "hostname", true); - - // creates cookie with ipaddress - final ServerConfiguration conf = this.conf; - conf.setUseHostNameAsBookieID(true); // sets to hostname - Cookie cookie = Cookie.readFromRegistrationManager(rm, conf).getValue(); - Cookie.Builder cookieBuilder = Cookie.newBuilder(cookie); - conf.setUseHostNameAsBookieID(false); // sets to hostname - - final String newBookieHost = BookieImpl.getBookieAddress(conf).toString(); - cookieBuilder.setBookieId(newBookieHost); - - cookieBuilder.build().writeToRegistrationManager(rm, conf, Version.NEW); - verifyCookieInZooKeeper(conf, 2); - - // again issue hostname cmd - BookieShell bkShell = new BookieShell(); - conf.setUseHostNameAsBookieID(true); // sets to hostname - bkShell.setConf(conf); - String[] argv = new String[] { "updatecookie", "-b", "hostname" }; - Assert.assertEquals("Failed to return the error code!", 0, bkShell.run(argv)); - - conf.setUseHostNameAsBookieID(true); - cookie = Cookie.readFromRegistrationManager(rm, conf).getValue(); - Assert.assertFalse("Cookie has created with IP!", cookie.isBookieHostCreatedFromIp()); - // ensure the old cookie is deleted - verifyCookieInZooKeeper(conf, 1); - } - - /** - * updatecookie to hostname. - */ - @Test - public void testDuplicateUpdateCookieIpAddress() throws Exception { - String[] argv = new String[] { "updatecookie", "-b", "ip" }; - final ServerConfiguration conf = this.conf; - conf.setUseHostNameAsBookieID(true); - updateCookie(argv, -1, conf); - } - - @Test - public void testWhenNoCookieExists() throws Exception { - String zkCookiePath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf) - + "/" + COOKIE_NODE + "/" + BookieImpl.getBookieAddress(conf); - Assert.assertNotNull("Cookie path doesn't still exists!", zkc.exists(zkCookiePath, false)); - zkc.delete(zkCookiePath, -1); - Assert.assertNull("Cookie path still exists!", zkc.exists(zkCookiePath, false)); - - BookieShell bkShell = new BookieShell(); - conf.setUseHostNameAsBookieID(true); - bkShell.setConf(conf); - String[] argv = new String[] { "updatecookie", "-b", "hostname" }; - Assert.assertEquals("Failed to return the error code!", -1, bkShell.run(argv)); - } - - private void verifyCookieInZooKeeper(ServerConfiguration conf, int expectedCount) throws KeeperException, - InterruptedException { - List cookies; - String bookieCookiePath1 = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf) + "/" + COOKIE_NODE; - cookies = zkc.getChildren(bookieCookiePath1, false); - Assert.assertEquals("Wrongly updated the cookie!", expectedCount, cookies.size()); - } - - private void updateCookie(String option, String optionVal, boolean useHostNameAsBookieID) throws Exception { - updateCookie(option, optionVal, useHostNameAsBookieID, false); - } - - private void updateCookie(String option, String optionVal, boolean useHostNameAsBookieID, boolean useShortHostName) - throws Exception { - conf.setUseHostNameAsBookieID(!useHostNameAsBookieID); - Cookie cookie = Cookie.readFromRegistrationManager(rm, conf).getValue(); - final boolean previousBookieID = cookie.isBookieHostCreatedFromIp(); - Assert.assertEquals("Wrong cookie!", useHostNameAsBookieID, previousBookieID); - - LOG.info("Perform updatecookie command"); - ServerConfiguration newconf = new ServerConfiguration(conf); - newconf.setUseHostNameAsBookieID(useHostNameAsBookieID); - newconf.setUseShortHostName(useShortHostName); - BookieShell bkShell = new BookieShell(); - bkShell.setConf(newconf); - String[] argv = new String[] { "updatecookie", option, optionVal }; - Assert.assertEquals("Failed to return exit code!", 0, bkShell.run(argv)); - - newconf.setUseHostNameAsBookieID(useHostNameAsBookieID); - newconf.setUseShortHostName(useShortHostName); - cookie = Cookie.readFromRegistrationManager(rm, newconf).getValue(); - Assert.assertEquals("Wrongly updated cookie!", previousBookieID, !cookie.isBookieHostCreatedFromIp()); - Assert.assertEquals("Wrongly updated cookie!", useHostNameAsBookieID, !cookie.isBookieHostCreatedFromIp()); - verifyCookieInZooKeeper(newconf, 1); - - for (File journalDir : conf.getJournalDirs()) { - journalDir = BookieImpl.getCurrentDirectory(journalDir); - Cookie jCookie = Cookie.readFromDirectory(journalDir); - jCookie.verify(cookie); - } - File[] ledgerDir = BookieImpl.getCurrentDirectories(conf.getLedgerDirs()); - for (File dir : ledgerDir) { - Cookie lCookie = Cookie.readFromDirectory(dir); - lCookie.verify(cookie); - } - } - - private void updateCookie(String[] argv, int exitCode, ServerConfiguration conf) throws KeeperException, - InterruptedException, IOException, UnknownHostException, Exception { - LOG.info("Perform updatecookie command"); - BookieShell bkShell = new BookieShell(); - bkShell.setConf(conf); - - Assert.assertEquals("Failed to return exit code!", exitCode, bkShell.run(argv)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java deleted file mode 100644 index e484f91133b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java +++ /dev/null @@ -1,400 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintStream; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.Arrays; -import java.util.List; -import org.apache.bookkeeper.client.ClientUtil; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.bookkeeper.util.PortManager; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the protocol upgrade procedure. - */ -public class UpgradeTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(FileInfo.class); - - private static final int bookiePort = PortManager.nextFreePort(); - - public UpgradeTest() { - super(0); - } - - static void writeLedgerDirWithIndexDir(File ledgerDir, - File indexDir, - byte[] masterKey) - throws Exception { - long ledgerId = 1; - - File fn = new File(indexDir, IndexPersistenceMgr.getLedgerName(ledgerId)); - fn.getParentFile().mkdirs(); - FileInfo fi = new FileInfo(fn, masterKey, FileInfo.CURRENT_HEADER_VERSION); - // force creation of index file - fi.write(new ByteBuffer[]{ ByteBuffer.allocate(0) }, 0); - fi.close(true); - - long logId = 0; - ByteBuffer logfileHeader = ByteBuffer.allocate(1024); - logfileHeader.put("BKLO".getBytes()); - FileChannel logfile = new RandomAccessFile( - new File(ledgerDir, Long.toHexString(logId) + ".log"), "rw").getChannel(); - logfile.write((ByteBuffer) logfileHeader.clear()); - logfile.close(); - } - - static void writeLedgerDir(File dir, - byte[] masterKey) - throws Exception { - long ledgerId = 1; - - File fn = new File(dir, IndexPersistenceMgr.getLedgerName(ledgerId)); - fn.getParentFile().mkdirs(); - FileInfo fi = new FileInfo(fn, masterKey, FileInfo.CURRENT_HEADER_VERSION); - // force creation of index file - fi.write(new ByteBuffer[]{ ByteBuffer.allocate(0) }, 0); - fi.close(true); - - long logId = 0; - ByteBuffer logfileHeader = ByteBuffer.allocate(1024); - logfileHeader.put("BKLO".getBytes()); - FileChannel logfile = new RandomAccessFile( - new File(dir, Long.toHexString(logId) + ".log"), "rw").getChannel(); - logfile.write((ByteBuffer) logfileHeader.clear()); - logfile.close(); - } - - static JournalChannel writeJournal(File journalDir, int numEntries, byte[] masterKey) - throws Exception { - long logId = System.currentTimeMillis(); - JournalChannel jc = new JournalChannel(journalDir, logId); - - BufferedChannel bc = jc.getBufferedChannel(); - - long ledgerId = 1; - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'X'); - long lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - - for (int i = 1; i <= numEntries; i++) { - ByteBuf packet = ClientUtil.generatePacket(ledgerId, i, lastConfirmed, - i * data.length, data); - lastConfirmed = i; - ByteBuffer lenBuff = ByteBuffer.allocate(4); - lenBuff.putInt(packet.readableBytes()); - lenBuff.flip(); - - bc.write(Unpooled.wrappedBuffer(lenBuff)); - bc.write(packet); - packet.release(); - } - bc.flushAndForceWrite(false); - - return jc; - } - - static File initV1JournalDirectory(File d) throws Exception { - writeJournal(d, 100, "foobar".getBytes()).close(); - return d; - } - - static File initV1LedgerDirectory(File d) throws Exception { - writeLedgerDir(d, "foobar".getBytes()); - return d; - } - - static File initV1LedgerDirectoryWithIndexDir(File ledgerDir, - File indexDir) throws Exception { - writeLedgerDirWithIndexDir(ledgerDir, indexDir, "foobar".getBytes()); - return ledgerDir; - } - - static void createVersion2File(File dir) throws Exception { - File versionFile = new File(dir, "VERSION"); - - FileOutputStream fos = new FileOutputStream(versionFile); - BufferedWriter bw = null; - try { - bw = new BufferedWriter(new OutputStreamWriter(fos)); - bw.write(String.valueOf(2)); - } finally { - if (bw != null) { - bw.close(); - } - fos.close(); - } - } - - static File initV2JournalDirectory(File d) throws Exception { - createVersion2File(initV1JournalDirectory(d)); - return d; - } - - static File initV2LedgerDirectory(File d) throws Exception { - createVersion2File(initV1LedgerDirectory(d)); - return d; - } - - static File initV2LedgerDirectoryWithIndexDir(File ledgerDir, File indexDir) throws Exception { - initV1LedgerDirectoryWithIndexDir(ledgerDir, indexDir); - createVersion2File(ledgerDir); - createVersion2File(indexDir); - return ledgerDir; - } - - private static void testUpgradeProceedure(String zkServers, String journalDir, String ledgerDir, String indexDir) - throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri("zk://" + zkServers + "/ledgers"); - conf.setJournalDirName(journalDir) - .setLedgerDirNames(new String[]{ledgerDir}) - .setIndexDirName(new String[]{indexDir}) - .setBookiePort(bookiePort); - Bookie b = null; - - try (MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - RegistrationManager rm = metadataDriver.createRegistrationManager()) { - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver).withRegistrationManager(rm).build(); - b = new TestBookieImpl(resources); - fail("Shouldn't have been able to start"); - } catch (IOException e) { - // correct behaviour - assertTrue("wrong exception", e.getMessage().contains("upgrade needed")); - } - - FileSystemUpgrade.upgrade(conf); // should work fine - try (MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - RegistrationManager rm = metadataDriver.createRegistrationManager()) { - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver).withRegistrationManager(rm).build(); - b = new TestBookieImpl(resources); - b.start(); - b.shutdown(); - } - b = null; - - FileSystemUpgrade.rollback(conf); - try (MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - RegistrationManager rm = metadataDriver.createRegistrationManager()) { - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver).withRegistrationManager(rm).build(); - b = new TestBookieImpl(resources); - fail("Shouldn't have been able to start"); - } catch (IOException e) { - // correct behaviour - assertTrue("wrong exception", e.getMessage().contains("upgrade needed")); - } - - FileSystemUpgrade.upgrade(conf); - FileSystemUpgrade.finalizeUpgrade(conf); - try (MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - RegistrationManager rm = metadataDriver.createRegistrationManager()) { - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver).withRegistrationManager(rm).build(); - b = new TestBookieImpl(resources); - b.start(); - b.shutdown(); - } - b = null; - } - - @Test - public void testUpgradeV1toCurrent() throws Exception { - File journalDir = initV1JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV1LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - testUpgradeProceedure(zkUtil.getZooKeeperConnectString(), journalDir.getPath(), - ledgerDir.getPath(), ledgerDir.getPath()); - } - - @Test - public void testUpgradeV1toCurrentWithIndexDir() throws Exception { - File journalDir = initV1JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File indexDir = tmpDirs.createNew("bookie", "index"); - File ledgerDir = initV1LedgerDirectoryWithIndexDir( - tmpDirs.createNew("bookie", "ledger"), indexDir); - testUpgradeProceedure(zkUtil.getZooKeeperConnectString(), journalDir.getPath(), - ledgerDir.getPath(), indexDir.getPath()); - } - - @Test - public void testUpgradeV2toCurrent() throws Exception { - File journalDir = initV2JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = initV2LedgerDirectory(tmpDirs.createNew("bookie", "ledger")); - File indexDir = tmpDirs.createNew("bookie", "index"); - testUpgradeProceedure(zkUtil.getZooKeeperConnectString(), journalDir.getPath(), - ledgerDir.getPath(), indexDir.getPath()); - } - - @Test - public void testUpgradeV2toCurrentWithIndexDir() throws Exception { - File journalDir = initV2JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File indexDir = tmpDirs.createNew("bookie", "index"); - File ledgerDir = initV2LedgerDirectoryWithIndexDir( - tmpDirs.createNew("bookie", "ledger"), indexDir); - testUpgradeProceedure(zkUtil.getZooKeeperConnectString(), journalDir.getPath(), - ledgerDir.getPath(), indexDir.getPath()); - } - - @Test - public void testUpgradeCurrent() throws Exception { - testUpgradeCurrent(false); - } - - @Test - public void testUpgradeCurrentWithIndexDir() throws Exception { - testUpgradeCurrent(true); - } - - public void testUpgradeCurrent(boolean hasIndexDir) throws Exception { - File journalDir = initV2JournalDirectory(tmpDirs.createNew("bookie", "journal")); - File ledgerDir = tmpDirs.createNew("bookie", "ledger"); - File indexDir = ledgerDir; - if (hasIndexDir) { - indexDir = tmpDirs.createNew("bookie", "index"); - initV2LedgerDirectoryWithIndexDir(ledgerDir, indexDir); - } else { - initV2LedgerDirectory(ledgerDir); - } - - testUpgradeProceedure(zkUtil.getZooKeeperConnectString(), journalDir.getPath(), - ledgerDir.getPath(), indexDir.getPath()); - - // Upgrade again - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[] { ledgerDir.getPath() }) - .setBookiePort(bookiePort) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - FileSystemUpgrade.upgrade(conf); // should work fine with current directory - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - conf, NullStatsLogger.INSTANCE); - RegistrationManager rm = metadataDriver.createRegistrationManager(); - - TestBookieImpl.Resources resources = new TestBookieImpl.ResourceBuilder(conf) - .withMetadataDriver(metadataDriver).withRegistrationManager(rm).build(); - Bookie b = new TestBookieImpl(resources); - b.start(); - b.shutdown(); - } - - @Test - public void testCommandLine() throws Exception { - PrintStream origerr = System.err; - PrintStream origout = System.out; - - File output = IOUtils.createTempFileAndDeleteOnExit("bookie", "stdout"); - File erroutput = IOUtils.createTempFileAndDeleteOnExit("bookie", "stderr"); - System.setOut(new PrintStream(output)); - System.setErr(new PrintStream(erroutput)); - try { - FileSystemUpgrade.main(new String[] { "-h" }); - try { - // test without conf - FileSystemUpgrade.main(new String[] { "-u" }); - fail("Should have failed"); - } catch (IllegalArgumentException iae) { - assertTrue("Wrong exception " + iae.getMessage(), - iae.getMessage().contains("without configuration")); - } - File f = IOUtils.createTempFileAndDeleteOnExit("bookie", "tmpconf"); - try { - // test without upgrade op - FileSystemUpgrade.main(new String[] { "--conf", f.getPath() }); - fail("Should have failed"); - } catch (IllegalArgumentException iae) { - assertTrue("Wrong exception " + iae.getMessage(), - iae.getMessage().contains("Must specify -upgrade")); - } - } finally { - System.setOut(origout); - System.setErr(origerr); - } - } - - @Test - public void testFSUGetAllDirectories() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - final File journalDir = tmpDirs.createNew("bookie", "journal"); - final File ledgerDir1 = tmpDirs.createNew("bookie", "ledger"); - final File ledgerDir2 = tmpDirs.createNew("bookie", "ledger"); - - // test1 - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir1.getPath(), ledgerDir2.getPath()}) - .setIndexDirName(new String[]{ledgerDir1.getPath(), ledgerDir2.getPath()}); - List allDirectories = FileSystemUpgrade.getAllDirectories(conf); - assertEquals(3, allDirectories.size()); - - // test2 - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir1.getPath(), ledgerDir2.getPath()}) - .setIndexDirName(new String[]{ledgerDir2.getPath(), ledgerDir1.getPath()}); - allDirectories = FileSystemUpgrade.getAllDirectories(conf); - assertEquals(3, allDirectories.size()); - - final File indexDir1 = tmpDirs.createNew("bookie", "index"); - final File indexDir2 = tmpDirs.createNew("bookie", "index"); - - // test3 - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir1.getPath(), ledgerDir2.getPath()}) - .setIndexDirName(new String[]{indexDir1.getPath(), indexDir2.getPath()}); - allDirectories = FileSystemUpgrade.getAllDirectories(conf); - assertEquals(5, allDirectories.size()); - - // test4 - conf.setJournalDirName(journalDir.getPath()) - .setLedgerDirNames(new String[]{ledgerDir1.getPath(), ledgerDir2.getPath()}) - .setIndexDirName(new String[]{indexDir2.getPath(), indexDir1.getPath()}); - allDirectories = FileSystemUpgrade.getAllDirectories(conf); - assertEquals(5, allDirectories.size()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/CookieValidationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/CookieValidationTest.java deleted file mode 100644 index 158bde903fc..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/CookieValidationTest.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie.datainteg; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Lists; -import java.io.File; -import java.io.FileOutputStream; -import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.MockRegistrationManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the DataIntegrityCookieValidation implementation of CookieValidation. - */ -@SuppressWarnings("deprecation") -public class CookieValidationTest { - private static Logger log = LoggerFactory.getLogger(CookieValidationTest.class); - final TmpDirs tmpDirs = new TmpDirs(); - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - } - - private File initializedDir() throws Exception { - File dir = tmpDirs.createNew("cookie", "validation"); - BookieImpl.checkDirectoryStructure(BookieImpl.getCurrentDirectory(dir)); - return dir; - } - - private static ServerConfiguration serverConf(boolean stampMissingCookies) { - ServerConfiguration conf = new ServerConfiguration(); - conf.setDataIntegrityStampMissingCookiesEnabled(stampMissingCookies); - conf.setAdvertisedAddress("foobar"); - return conf; - } - - private Versioned genCookie(ServerConfiguration conf) throws UnknownHostException { - return new Versioned<>(Cookie.generateCookie(conf).build().toString() - .getBytes(StandardCharsets.UTF_8), Version.NEW); - } - - @Test - public void testNoZkCookieAndEmptyDirsStampsNewCookie() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(false); - BookieId bookieId = BookieImpl.getBookieId(conf); - MockRegistrationManager regManager = new MockRegistrationManager(); - DataIntegrityCookieValidation v = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v.checkCookies(dirs); - - byte[] cookieBytes = regManager.readCookie(bookieId).getValue(); - assertThat(cookieBytes, notNullValue()); - assertThat(cookieBytes.length, greaterThan(0)); - - Cookie regManagerCookie = Cookie.parseFromBytes(cookieBytes); - - for (File d : dirs) { - assertThat(Cookie.readFromDirectory(d), equalTo(regManagerCookie)); - } - } - - @Test(expected = BookieException.InvalidCookieException.class) - public void testZkCookieAndEmptyDirsRaisesErrorWithoutMissingCookieStamping() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(false); - BookieId bookieId = BookieImpl.getBookieId(conf); - MockRegistrationManager regManager = new MockRegistrationManager(); - regManager.writeCookie(bookieId, genCookie(conf)); - DataIntegrityCookieValidation v = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v.checkCookies(dirs); - } - - @Test - public void testZkCookieAndEmptyDirsStampsNewCookieWithMissingCookieStamping() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(true); - BookieId bookieId = BookieImpl.getBookieId(conf); - MockRegistrationManager regManager = new MockRegistrationManager(); - regManager.writeCookie(bookieId, genCookie(conf)); - DataIntegrityCookieValidation v = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v.checkCookies(dirs); - - byte[] cookieBytes = regManager.readCookie(bookieId).getValue(); - assertThat(cookieBytes, notNullValue()); - assertThat(cookieBytes.length, greaterThan(0)); - - Cookie regManagerCookie = Cookie.parseFromBytes(cookieBytes); - - for (File d : dirs) { - assertThat(Cookie.readFromDirectory(d), equalTo(regManagerCookie)); - } - } - - @Test(expected = BookieException.InvalidCookieException.class) - public void testMissingZKCookieRaisesError() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(true); - - MockRegistrationManager regManager = new MockRegistrationManager(); - DataIntegrityCookieValidation v1 = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v1.checkCookies(dirs); - - MockRegistrationManager blankRegManager = new MockRegistrationManager(); - DataIntegrityCookieValidation v2 = new DataIntegrityCookieValidation( - conf, blankRegManager, new MockDataIntegrityCheck()); - v2.checkCookies(dirs); - } - - @Test - public void testMatchingCookiesTakesNoAction() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(true); - - MockRegistrationManager regManager = new MockRegistrationManager(); - DataIntegrityCookieValidation v1 = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v1.checkCookies(dirs); // stamp original cookies - - DataIntegrityCookieValidation v2 = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v2.checkCookies(dirs); // should find cookies and return successfully - } - - @Test - public void testEmptyDirectoryTriggersIntegrityCheck() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - ServerConfiguration conf = serverConf(true); - - MockRegistrationManager regManager = new MockRegistrationManager(); - MockDataIntegrityCheck dataIntegCheck = spy(new MockDataIntegrityCheck()); - DataIntegrityCookieValidation v1 = new DataIntegrityCookieValidation( - conf, regManager, dataIntegCheck); - v1.checkCookies(dirs); // stamp original cookies - verify(dataIntegCheck, times(0)).runPreBootCheck("INVALID_COOKIE"); - - dirs.add(initializedDir()); - v1.checkCookies(dirs); // stamp original cookies - verify(dataIntegCheck, times(1)).runPreBootCheck("INVALID_COOKIE"); - - v1.checkCookies(dirs); // stamp original cookies - verify(dataIntegCheck, times(1)).runPreBootCheck("INVALID_COOKIE"); - } - - @Test - public void testErrorInIntegrityCheckPreventsStamping() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(true); - - MockRegistrationManager regManager = spy(new MockRegistrationManager()); - MockDataIntegrityCheck dataIntegCheck = spy(new MockDataIntegrityCheck() { - @Override - public CompletableFuture runPreBootCheck(String reason) { - return FutureUtils.exception(new BookieException.InvalidCookieException("blah")); - } - }); - - DataIntegrityCookieValidation v1 = new DataIntegrityCookieValidation( - conf, regManager, dataIntegCheck); - - v1.checkCookies(dirs); // stamp original cookies - verify(dataIntegCheck, times(0)).runPreBootCheck("INVALID_COOKIE"); - verify(regManager, times(1)).writeCookie(any(), any()); - - // add a directory to trigger data integrity check - dirs.add(initializedDir()); - try { - v1.checkCookies(dirs); // stamp original cookies - Assert.fail("failure of data integrity should fail cookie check"); - } catch (BookieException.InvalidCookieException e) { - // expected - } - verify(dataIntegCheck, times(1)).runPreBootCheck("INVALID_COOKIE"); - verify(regManager, times(1)).writeCookie(any(), any()); - - // running the check again should run data integrity again, as stamping didn't happen - try { - v1.checkCookies(dirs); // stamp original cookies - Assert.fail("failure of data integrity should fail cookie check"); - } catch (BookieException.InvalidCookieException e) { - // expected - } - verify(dataIntegCheck, times(2)).runPreBootCheck("INVALID_COOKIE"); - verify(regManager, times(1)).writeCookie(any(), any()); - } - - @Test - public void testChangingBookieIdRaisesError() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - ServerConfiguration conf = serverConf(true); - MockRegistrationManager regManager = new MockRegistrationManager(); - DataIntegrityCookieValidation v1 = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v1.checkCookies(dirs); // stamp original cookies - - conf.setAdvertisedAddress("barfoo"); - DataIntegrityCookieValidation v2 = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - try { - v2.checkCookies(dirs); // should fail as cookie not found in ZK, but exists in dirs - Assert.fail("Check shouldn't have succeeded with new bookieId"); - } catch (BookieException.InvalidCookieException ice) { - // expected - } - - conf.setAdvertisedAddress("foobar"); - DataIntegrityCookieValidation v3 = new DataIntegrityCookieValidation( - conf, regManager, new MockDataIntegrityCheck()); - v3.checkCookies(dirs); // should succeed as the cookie is same as before - } - - @Test - public void testMismatchLocalCookie() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(true); - - MockDataIntegrityCheck dataIntegCheck = spy(new MockDataIntegrityCheck()); - MockRegistrationManager regManager = spy(new MockRegistrationManager()); - DataIntegrityCookieValidation v1 = new DataIntegrityCookieValidation( - conf, regManager, dataIntegCheck); - v1.checkCookies(dirs); // stamp original cookies - - verify(dataIntegCheck, times(0)).runPreBootCheck("INVALID_COOKIE"); - verify(regManager, times(1)).writeCookie(any(), any()); - - Cookie current = Cookie.readFromDirectory(dirs.get(0)); - Cookie mismatch = Cookie.newBuilder(current).setBookieId("mismatch:3181").build(); - mismatch.writeToDirectory(dirs.get(0)); - assertThat(current, not(Cookie.readFromDirectory(dirs.get(0)))); - - v1.checkCookies(dirs); - verify(dataIntegCheck, times(1)).runPreBootCheck("INVALID_COOKIE"); - verify(regManager, times(2)).writeCookie(any(), any()); - - Cookie afterCheck = Cookie.readFromDirectory(dirs.get(0)); - assertThat(afterCheck, equalTo(current)); - } - - @Test(expected = BookieException.InvalidCookieException.class) - public void testCorruptLocalCookie() throws Exception { - List dirs = Lists.newArrayList(initializedDir(), - initializedDir()); - - ServerConfiguration conf = serverConf(true); - - MockDataIntegrityCheck dataIntegCheck = spy(new MockDataIntegrityCheck()); - MockRegistrationManager regManager = spy(new MockRegistrationManager()); - DataIntegrityCookieValidation v1 = new DataIntegrityCookieValidation( - conf, regManager, dataIntegCheck); - v1.checkCookies(dirs); // stamp original cookies - - verify(dataIntegCheck, times(0)).runPreBootCheck("INVALID_COOKIE"); - verify(regManager, times(1)).writeCookie(any(), any()); - - File cookieFile = new File(dirs.get(0), BookKeeperConstants.VERSION_FILENAME); - try (FileOutputStream out = new FileOutputStream(cookieFile)) { - out.write(0xdeadbeef); - } - v1.checkCookies(dirs); // should throw - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityCheckTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityCheckTest.java deleted file mode 100644 index 6d4c7a122f0..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityCheckTest.java +++ /dev/null @@ -1,1540 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie.datainteg; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.not; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyLong; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.netty.buffer.ByteBuf; -import io.reactivex.rxjava3.core.Single; -import io.reactivex.rxjava3.exceptions.CompositeException; -import io.reactivex.rxjava3.observers.TestObserver; -import io.reactivex.rxjava3.schedulers.Schedulers; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import java.util.stream.LongStream; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.LedgerStorage.StorageState; -import org.apache.bookkeeper.bookie.MockLedgerStorage; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.MockTicker; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.MockLedgerManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Test of DataIntegrityCheckImpl. - */ -@SuppressWarnings("deprecation") -public class DataIntegrityCheckTest { - private static final byte[] PASSWD = new byte[0]; - - private final BookieId bookie1 = BookieId.parse("bookie1:3181"); - private final BookieId bookie2 = BookieId.parse("bookie2:3181"); - private final BookieId bookie3 = BookieId.parse("bookie3:3181"); - private final BookieId bookie4 = BookieId.parse("bookie4:3181"); - private final BookieId bookie5 = BookieId.parse("bookie5:3181"); - - private OrderedExecutor executor = null; - - @Before - public void setup() throws Exception { - executor = OrderedExecutor.newBuilder().numThreads(1).name("test").build(); - } - - @After - public void teardown() throws Exception { - if (executor != null) { - executor.shutdownNow(); - } - } - - private static ServerConfiguration serverConf() { - ServerConfiguration conf = new ServerConfiguration(); - conf.setAdvertisedAddress("foobar"); - return conf; - } - - private LedgerMetadataBuilder newMetadataWithEnsemble( - long ledgerId, - BookieId... bookies) { - return LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(bookies.length) - .withWriteQuorumSize(bookies.length) - .withAckQuorumSize(bookies.length) - .newEnsembleEntry(0, Lists.newArrayList(bookies)); - } - - private LedgerMetadataBuilder newClosedMetadataWithEnsemble(long ledgerId, - long numEntries, - BookieId... bookies) { - return LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(bookies.length) - .withWriteQuorumSize(bookies.length) - .withAckQuorumSize(bookies.length) - .newEnsembleEntry(0, Lists.newArrayList(bookies)) - .withLastEntryId(numEntries - 1) - .withLength(128 * numEntries) - .withClosedState(); - } - - @Test - public void testPrebootBookieIdInOpenSegmentMarkedInLimbo() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - lm.createLedgerMetadata(0xbeefL, newMetadataWithEnsemble(0xbeefL, bookieId).build()).get(); - - MockLedgerStorage storage = new MockLedgerStorage(); - assertThat(storage.ledgerExists(0xbeefL), is(false)); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(BookieImpl.getBookieId(conf), lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()); - impl.runPreBootCheck("test").get(); - - assertThat(storage.hasLimboState(0xbeefL), is(true)); - assertThat(storage.isFenced(0xbeefL), is(true)); - } - - @Test - public void testPrebootFencedMarkedInLimbo() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - lm.createLedgerMetadata(0xbeefL, - newMetadataWithEnsemble(0xbeefL, - BookieImpl.getBookieId(conf)).withInRecoveryState().build()).get(); - - MockLedgerStorage storage = new MockLedgerStorage(); - assertThat(storage.ledgerExists(0xbeefL), is(false)); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()); - impl.runPreBootCheck("test").get(); - - assertThat(storage.hasLimboState(0xbeefL), is(true)); - assertThat(storage.isFenced(0xbeefL), is(true)); - } - - @Test - public void testPrebootClosedNotMarkedInLimbo() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - lm.createLedgerMetadata(0xbeefL, - newMetadataWithEnsemble(0xbeefL, BookieImpl.getBookieId(conf)).withClosedState() - .withLength(100).withLastEntryId(1).build()).get(); - - MockLedgerStorage storage = new MockLedgerStorage(); - assertThat(storage.ledgerExists(0xbeefL), is(false)); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()); - impl.runPreBootCheck("test").get(); - - assertThat(storage.hasLimboState(0xbeefL), is(false)); - assertThat(storage.isFenced(0xbeefL), is(false)); - } - - @Test - public void testPrebootFlushCalled() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - lm.createLedgerMetadata(0xbeefL, newMetadataWithEnsemble( - 0xbeefL, BookieImpl.getBookieId(conf)).build()).get(); - - MockLedgerStorage storage = spy(new MockLedgerStorage()); - assertThat(storage.ledgerExists(0xbeefL), is(false)); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()); - verify(storage, times(0)).flush(); - impl.runPreBootCheck("test").get(); - verify(storage, times(1)).flush(); - - assertThat(storage.hasLimboState(0xbeefL), is(true)); - assertThat(storage.isFenced(0xbeefL), is(true)); - } - - @Test(expected = ExecutionException.class) - public void testFailureInPrebootMarkFailsAll() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - lm.createLedgerMetadata(0xbeedL, newMetadataWithEnsemble(0xbeedL, bookieId).build()).get(); - lm.createLedgerMetadata(0xbeefL, newMetadataWithEnsemble(0xbeefL, bookieId).build()).get(); - lm.createLedgerMetadata(0xbee0L, newMetadataWithEnsemble(0xbee0L, bookieId).build()).get(); - - MockLedgerStorage storage = new MockLedgerStorage() { - @Override - public void setLimboState(long ledgerId) throws IOException { - if (ledgerId == 0xbeefL) { - throw new IOException("boom!"); - } else { - super.setLimboState(ledgerId); - } - } - }; - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()); - impl.runPreBootCheck("test").get(); - } - - @Test - public void testRecoverLimboOpensAndClears() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - return Single.just(newClosedMetadataWithEnsemble(ledgerId, -1, bookieId, bookie1).build()); - } - }; - - Map ledgers = new HashMap<>(); - ledgers.put(0xf00L, newMetadataWithEnsemble(0xf00L, bookieId, bookie1).build()); - storage.setMasterKey(0xf00L, PASSWD); - storage.setLimboState(0xf00L); - ledgers.put(0xdeadL, newMetadataWithEnsemble(0xdeadL, bookieId, bookie1).build()); - storage.setMasterKey(0xdeadL, PASSWD); - storage.setLimboState(0xdeadL); - - Set results = impl.checkAndRecoverLedgers( - ledgers, "test").get(); - - assertThat(results.stream().filter(r -> r.isOK()).count(), equalTo(2L)); - verify(storage, times(1)).clearLimboState(0xf00L); - verify(storage, times(1)).clearLimboState(0xdeadL); - } - - @Test - public void testRecoverLimboErrorOnOpenOnlyAffectsThatOne() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - if (ledgerId == 0xf00L) { - return Single.error(new BKException.BKReadException()); - } else { - return Single.just(newClosedMetadataWithEnsemble(ledgerId, 0, bookieId, bookie1).build()); - } - } - }; - - Map ledgers = new HashMap<>(); - ledgers.put(0xf00L, newMetadataWithEnsemble(0xf00L, bookieId, bookie1).build()); - storage.setMasterKey(0xf00L, PASSWD); - storage.setLimboState(0xf00L); - ledgers.put(0xdeadL, newMetadataWithEnsemble(0xdeadL, bookieId, bookie1).build()); - storage.setMasterKey(0xdeadL, PASSWD); - storage.setLimboState(0xdeadL); - - Set results = impl.checkAndRecoverLedgers(ledgers, "test").get(); - - assertThat(results.stream().filter(r -> r.isOK()).count(), equalTo(1L)); - assertThat(results.stream().filter(r -> r.isOK()).map(r -> r.getLedgerId()).findFirst().get(), - equalTo(0xdeadL)); - assertThat(results.stream().filter(r -> r.isError()).count(), equalTo(1L)); - assertThat(results.stream().filter(r -> r.isError()).map(r -> r.getLedgerId()).findFirst().get(), - equalTo(0xf00L)); - - verify(storage, times(0)).clearLimboState(0xf00L); - verify(storage, times(1)).clearLimboState(0xdeadL); - } - - @Test - public void testRecoverLimboNoSuchLedger() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - if (ledgerId == 0xdeadL) { - return Single.error( - new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } else { - return Single.just(newClosedMetadataWithEnsemble(ledgerId, -1, bookieId, bookie1).build()); - } - } - }; - - Map ledgers = new HashMap<>(); - ledgers.put(0xf00L, newMetadataWithEnsemble(0xf00L, bookieId, bookie1).build()); - storage.setMasterKey(0xf00L, PASSWD); - storage.setLimboState(0xf00L); - ledgers.put(0xdeadL, newMetadataWithEnsemble(0xdeadL, bookieId, bookie1).build()); - storage.setMasterKey(0xdeadL, PASSWD); - storage.setLimboState(0xdeadL); - - Set results = impl.checkAndRecoverLedgers(ledgers, "test").get(); - - assertThat(results.stream().filter(r -> r.isOK()).count(), equalTo(1L)); - assertThat(results.stream().filter(r -> r.isOK()).map(r -> r.getLedgerId()).findFirst().get(), - equalTo(0xf00L)); - assertThat(results.stream().filter(r -> r.isMissing()).count(), equalTo(1L)); - assertThat(results.stream().filter(r -> r.isMissing()).map(r -> r.getLedgerId()).findFirst().get(), - equalTo(0xdeadL)); - - verify(storage, times(1)).clearLimboState(0xf00L); - verify(storage, times(0)).clearLimboState(0xdeadL); - } - - @Test - public void testRecoverLimboClearStateFailure() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public void clearLimboState(long ledgerId) throws IOException { - if (ledgerId == 0xf00L) { - throw new IOException("foobar"); - } - } - }); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - return Single.just(newClosedMetadataWithEnsemble(ledgerId, -1, bookieId, bookie1).build()); - } - }; - Map ledgers = new HashMap<>(); - ledgers.put(0xf00L, newMetadataWithEnsemble(0xf00L, bookieId, bookie1).build()); - storage.setMasterKey(0xf00L, PASSWD); - storage.setLimboState(0xf00L); - ledgers.put(0xdeadL, newMetadataWithEnsemble(0xdeadL, bookieId, bookie1).build()); - storage.setMasterKey(0xdeadL, PASSWD); - storage.setLimboState(0xdeadL); - - Set results = impl.checkAndRecoverLedgers(ledgers, "test").get(); - - verify(storage, times(0)).flush(); - } - - // TODO: what is this test? -// @Test -// public void testRecoverLimboFlushFailure() throws Exception { -// MockLedgerManager lm = new MockLedgerManager(); -// ServerConfiguration conf = serverConf(); -// BookieId bookieId = BookieImpl.getBookieId(conf); -// MockLedgerStorage storage = spy(new MockLedgerStorage() { -// @Override -// public void flush() throws IOException { -// throw new IOException("foobar"); -// } -// }); -// DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, -// mock(EntryCopier.class), -// mock(BookKeeperAdmin.class), -// Schedulers.io()) { -// @Override -// CompletableFuture recoverLedgerIgnoreMissing(long ledgerId) { -// return CompletableFuture.completedFuture(ledgerId); -// } -// }; -// Set ledgers = Sets.newHashSet(0xf00L, 0xdeadL); -// -// try { -// impl.recoverLedgersInLimbo(ledgers).get(); -// Assert.fail("Shouldn't continue on an IOException"); -// } catch (ExecutionException ee) { -// assertThat(ee.getCause(), instanceOf(IOException.class)); -// } -// assertThat(results.stream().filter(r -> r.isOK()).count(), equalTo(1L)); -// assertThat(results.stream().filter(r -> r.isOK()).map(r -> r.getLedgerId()).findFirst().get(), -// equalTo(0xdeadL)); -// assertThat(results.stream().filter(r -> r.isError()).count(), equalTo(1L)); -// assertThat(results.stream().filter(r -> r.isError()).map(r -> r.getLedgerId()).findFirst().get(), -// equalTo(0xf00L)); -// -// verify(storage, times(1)).clearLimboState(0xf00L); -// verify(storage, times(1)).clearLimboState(0xdeadL); -// } - - @Test - public void testRecoverLimboManyLedgers() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - List cleared = new ArrayList<>(); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public void clearLimboState(long ledgerId) { - // not using spy for this because it takes 10ms per ledger to verify - cleared.add(ledgerId); - } - }); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - return Single.just(newClosedMetadataWithEnsemble(ledgerId, -1, bookieId, bookie1).build()); - } - }; - final long numLedgers = 10000; - long first = 1; - long last = first + numLedgers; - - Map ledgers = new HashMap<>(); - for (long i = first; i < last; i++) { - LedgerMetadata metadata = newMetadataWithEnsemble(i, bookieId, bookie1).build(); - ledgers.put(i, metadata); - storage.setMasterKey(i, metadata.getPassword()); - storage.setLimboState(i); - } - assertThat(ledgers.size(), equalTo((int) numLedgers)); - - Set results = impl.checkAndRecoverLedgers(ledgers, "test").get(); - assertThat(results.size(), equalTo((int) numLedgers)); - assertThat(results.stream().filter(r -> r.isOK()).count(), equalTo(numLedgers)); - for (DataIntegrityCheckImpl.LedgerResult r : results) { - assertThat(r.isOK(), equalTo(true)); - ledgers.remove(r.getLedgerId()); - } - assertThat(ledgers.isEmpty(), equalTo(true)); - - Set clearedSet = Sets.newHashSet(cleared); - assertThat(clearedSet.size(), equalTo(cleared.size())); - for (long l : LongStream.range(first, last).toArray()) { - assertThat(l, isIn(clearedSet)); - } - verify(storage, times(10000)).clearLimboState(anyLong()); - } - - @Test - public void testRecoverLimboManyLedgersErrorOnFirst() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - List cleared = new ArrayList<>(); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public void clearLimboState(long ledgerId) { - // not using spy for this because it takes 10ms per ledger to verify - cleared.add(ledgerId); - } - }); - - final long numLedgers = 100; - long first = 1; - long last = first + numLedgers; - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - if (ledgerId == first) { - return Single.error( - new BKException.BKBookieHandleNotAvailableException()); - } else { - return Single.just(newClosedMetadataWithEnsemble(ledgerId, -1, bookieId, bookie1).build()); - } - } - }; - Map ledgers = new HashMap<>(); - for (long i = first; i < last; i++) { - LedgerMetadata metadata = newMetadataWithEnsemble(i, bookieId, bookie1).build(); - ledgers.put(i, metadata); - storage.setMasterKey(i, metadata.getPassword()); - storage.setLimboState(i); - } - assertThat(ledgers.size(), equalTo((int) numLedgers)); - - Set results = impl.checkAndRecoverLedgers(ledgers, "test").get(); - assertThat(results.size(), equalTo((int) numLedgers)); - assertThat(results.stream().filter(r -> r.isOK()).count(), equalTo(numLedgers - 1)); - assertThat(results.stream().filter(r -> r.isError()).count(), equalTo(1L)); - assertThat(results.stream().filter(r -> r.isError()).map(r -> r.getLedgerId()).findFirst().get(), - equalTo(first)); - Set clearedSet = Sets.newHashSet(cleared); - assertThat(clearedSet.size(), equalTo(cleared.size())); - for (long l : LongStream.range(first, last).toArray()) { - if (l == first) { - assertThat(l, not(isIn(clearedSet))); - } else { - assertThat(l, isIn(clearedSet)); - } - } - verify(storage, times((int) numLedgers - 1)).clearLimboState(anyLong()); - } - - @Test - public void testRecoverLimboNoLedgers() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - BookieId bookieId = BookieImpl.getBookieId(conf); - List cleared = new ArrayList<>(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookieId, lm, storage, - mock(EntryCopier.class), - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - return Single.just(newClosedMetadataWithEnsemble(ledgerId, -1, bookieId, bookie1).build()); - } - }; - ImmutableMap ledgers = ImmutableMap.of(); - Set resolved = - impl.checkAndRecoverLedgers(ledgers, "test").get(10, TimeUnit.SECONDS); - assertThat(resolved.isEmpty(), equalTo(true)); - verify(storage, times(0)).clearLimboState(anyLong()); - } - - - @Test - public void testRecoverSingleLedgerEntriesOnLedgerIDontHave() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie3, bookie2).build(); - bookieClient.getMockBookies().seedLedger(id1, metadata1); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertNoErrors(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); // because we passed it in - for (long i = 0; i <= metadata1.getLastEntryId(); i++) { - assertThat(storage.entryExists(id1, i), equalTo(false)); - } - } - - @Test - public void testRecoverSingleLedgerNotClosedOneEnsemble() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newMetadataWithEnsemble(id1, bookie1, bookie2).build(); - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertNoErrors(); - - LedgerMetadata md1 = newMetadataWithEnsemble(id1, bookie1).build(); - assertThat(storage.ledgerExists(id1), equalTo(false)); - } - - @Test - public void testRecoverSingleLedgerNoClosedMultiEnsembleBookieInClosed() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newMetadataWithEnsemble(id1, bookie1, bookie2) - .newEnsembleEntry(10L, Lists.newArrayList(bookie3, bookie2)).build(); - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id1, metadata1); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertNoErrors(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - for (long e = 0; e < 10; e++) { - assertThat(storage.entryExists(id1, e), equalTo(true)); - } - assertThat(storage.entryExists(id1, 10), equalTo(false)); - } - - @Test - public void testRecoverSingleLedgerNotClosedMultiEnsembleBookieInFinal() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newMetadataWithEnsemble(id1, bookie3, bookie2) - .newEnsembleEntry(10L, Lists.newArrayList(bookie1, bookie2)).build(); - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id1, metadata1); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertNoErrors(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - } - - @Test - public void testRecoverSingleLedgerLargeEnsembleStriped() throws Exception { - - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie4, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie4, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = LedgerMetadataBuilder.create() - .withId(id1) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(5) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2, bookie3, bookie4, bookie5)) - .withClosedState().withLastEntryId(10).withLength(1000) - .build(); - bookieClient.getMockBookies().seedLedgerForBookie(bookie1, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie5, id1, metadata1); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertNoErrors(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.entryExists(id1, 0), equalTo(false)); - assertThat(storage.entryExists(id1, 1), equalTo(false)); - assertThat(storage.entryExists(id1, 2), equalTo(true)); - assertThat(storage.entryExists(id1, 3), equalTo(true)); - assertThat(storage.entryExists(id1, 4), equalTo(false)); - assertThat(storage.entryExists(id1, 5), equalTo(false)); - assertThat(storage.entryExists(id1, 6), equalTo(false)); - assertThat(storage.entryExists(id1, 7), equalTo(true)); - assertThat(storage.entryExists(id1, 8), equalTo(true)); - assertThat(storage.entryExists(id1, 9), equalTo(false)); - assertThat(storage.entryExists(id1, 10), equalTo(false)); - } - - @Test - public void testRecoverSingleLedgerEntriesOnlyEntriesNeeded() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie3, bookie2) - .newEnsembleEntry(10, Lists.newArrayList(bookie1, bookie2)) - .newEnsembleEntry(100, Lists.newArrayList(bookie3, bookie2)).build(); - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id1, metadata1); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertNoErrors(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.entryExists(id1, 9), equalTo(false)); - for (long e = 10; e < 100; e++) { - assertThat(storage.entryExists(id1, e), equalTo(true)); - } - assertThat(storage.entryExists(id1, 100), equalTo(false)); - } - - @Test - public void testRecoverSingleLedgerEntriesOnlyEntriesNeededEverySecond() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - long added = 0; - storage.setMasterKey(id1, PASSWD); - for (long e = 0; e <= metadata1.getLastEntryId(); e++) { - if (e % 2 == 0) { - storage.addEntry(bookieClient.getMockBookies().generateEntry(id1, e, e - 1)); - added++; - } - } - assertThat(storage.ledgerExists(id1), equalTo(true)); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertNoErrors(); - - for (long e = 0; e <= metadata1.getLastEntryId(); e++) { - if (e % 2 == 0) { - verify(bookieClient, times(0)).readEntry(any(), eq(id1), eq(e), - any(), any(), anyInt()); - } - if (e % 2 == 1) { - verify(bookieClient, times(1)).readEntry(any(), eq(id1), eq(e), - any(), any(), anyInt()); - } - - assertThat(storage.entryExists(id1, e), equalTo(true)); - } - } - - @Test - public void testRecoverSingleLedgerErrorAtStart() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - - // only seed for ledger1 & ledger3 - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.setPreReadHook((bookie, ledger, entry) -> { - if (entry == 0L) { - return FutureUtils.exception(new BKException.BKReadException()); - } else { - return CompletableFuture.completedFuture(null); - } - }); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertError((t) -> { - return t instanceof BKException.BKReadException; - }); - assertThat(storage.entryExists(id1, 0), equalTo(false)); - for (long e = 1; e <= metadata1.getLastEntryId(); e++) { - assertThat(storage.entryExists(id1, e), equalTo(true)); - } - } - - @Test - public void testRecoverSingleLedgerErrorEverySecond() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - - // only seed for ledger1 & ledger3 - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.setPreReadHook((bookie, ledger, entry) -> { - if (entry % 2 == 0) { - return FutureUtils.exception(new BKException.BKReadException()); - } else { - return CompletableFuture.completedFuture(null); - } - }); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertError((t) -> { - if (t instanceof CompositeException) { - CompositeException e = (CompositeException) t; - for (Throwable t2 : e.getExceptions()) { - if (!(t2 instanceof BKException.BKReadException)) { - return false; - } - } - return e.getExceptions().size() == 500; - } else { - return false; - } - }); - for (long e = 0; e <= metadata1.getLastEntryId(); e++) { - if (e % 2 == 0) { - assertThat(storage.entryExists(id1, e), equalTo(false)); - } else { - assertThat(storage.entryExists(id1, e), equalTo(true)); - } - } - } - - @Test - public void testRecoverSingleLedgerErrorOneOnStore() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public long addEntry(ByteBuf entry) throws IOException, BookieException { - long entryId = extractEntryId(entry); - if (entryId > 10 && entryId <= 100) { - throw new IOException("Don't feel like storing these"); - } - return super.addEntry(entry); - } - }); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - // only seed for ledger1 & ledger3 - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - - TestObserver observer = TestObserver.create(); - impl.checkAndRecoverLedgerEntries(id1, metadata1, "test").subscribe(observer); - observer.await().assertError((t) -> { - if (t instanceof CompositeException) { - CompositeException e = (CompositeException) t; - for (Throwable t2 : e.getExceptions()) { - boolean failStore = t2 instanceof IOException; - if (!failStore) { - return false; - } - } - return e.getExceptions().size() == 90; - } else { - return false; - } - }); - for (long e = 0; e <= 10; e++) { - assertThat(storage.entryExists(id1, e), equalTo(true)); - } - for (long e = 11; e <= 100; e++) { - assertThat(storage.entryExists(id1, e), equalTo(false)); - } - for (long e = 101; e <= metadata1.getLastEntryId(); e++) { - assertThat(storage.entryExists(id1, e), equalTo(true)); - } - } - - @Test - public void testRecoverMultiLedgers() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id2, metadata2); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - Map ledgers = ImmutableMap.of( - id1, metadata1, id2, metadata2, id3, metadata3); - Set resolved = - impl.checkAndRecoverLedgers(ledgers, "test").get(10, TimeUnit.SECONDS); - assertThat(resolved.stream().filter(r -> r.isOK()).count(), equalTo(3L)); - assertThat(resolved.stream().filter(r -> r.isOK()).map(r -> r.getLedgerId()) - .collect(Collectors.toSet()), containsInAnyOrder(id1, id2, id3)); - for (long e = 0; e <= metadata1.getLastEntryId(); e++) { - assertThat(storage.entryExists(id1, e), equalTo(true)); - assertThat(storage.entryExists(id2, e), equalTo(true)); - assertThat(storage.entryExists(id3, e), equalTo(true)); - } - } - - @Test - public void testRecoverMultiLedgersOneUnavailable() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - // id2 will be unavailable because there's no entries - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - - Map ledgers = ImmutableMap.of( - id1, metadata1, id2, metadata2, id3, metadata3); - Set resolved = - impl.checkAndRecoverLedgers(ledgers, "test").get(10, TimeUnit.SECONDS); - assertThat(resolved.stream().filter(r -> r.isOK()).count(), equalTo(2L)); - assertThat(resolved.stream().filter(r -> r.isError()).count(), equalTo(1L)); - assertThat(resolved.stream().filter(r -> r.isOK()).map(r -> r.getLedgerId()) - .collect(Collectors.toSet()), containsInAnyOrder(id1, id3)); - for (long e = 0; e <= metadata1.getLastEntryId(); e++) { - assertThat(storage.entryExists(id1, e), equalTo(true)); - assertThat(storage.entryExists(id3, e), equalTo(true)); - } - } - - @Test - public void testRecoverMultiLedgersOneFailsToWriteLocally() throws Exception { - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public long addEntry(ByteBuf entry) throws IOException, BookieException { - if (extractLedgerId(entry) == id1 - && extractEntryId(entry) == 3) { - throw new IOException("Don't feel like storing this"); - } - return super.addEntry(entry); - } - }); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id2, metadata2); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - - Map ledgers = ImmutableMap.of( - id1, metadata1, id2, metadata2, id3, metadata3); - - Set resolved = - impl.checkAndRecoverLedgers(ledgers, "test").get(10, TimeUnit.SECONDS); - assertThat(resolved.stream().filter(r -> r.isOK()).count(), equalTo(2L)); - assertThat(resolved.stream().filter(r -> r.isOK()) - .map(r -> r.getLedgerId()).collect(Collectors.toSet()), - containsInAnyOrder(id2, id3)); - assertThat(resolved.stream().filter(r -> r.isError()) - .map(r -> r.getLedgerId()).collect(Collectors.toSet()), - containsInAnyOrder(id1)); - - for (long e = 0; e <= metadata1.getLastEntryId(); e++) { - assertThat(storage.entryExists(id1, e), equalTo(e != 3)); - assertThat(storage.entryExists(id2, e), equalTo(true)); - assertThat(storage.entryExists(id3, e), equalTo(true)); - } - } - - @Test - public void testRecoverMultiLedgersAllUnavailable() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - - Map ledgers = ImmutableMap.of( - id1, metadata1, id2, metadata2, id3, metadata3); - - Set resolved = - impl.checkAndRecoverLedgers(ledgers, "test").get(10, TimeUnit.SECONDS); - assertThat(resolved.stream().filter(r -> r.isOK()).count(), equalTo(0L)); - assertThat(resolved.stream().filter(r -> r.isError()).count(), equalTo(3L)); - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.entryExists(id1, 0), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(true)); - assertThat(storage.entryExists(id2, 0), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(true)); - assertThat(storage.entryExists(id3, 0), equalTo(false)); - } - - @Test - public void testEnsemblesContainBookie() throws Exception { - LedgerMetadata md1 = newMetadataWithEnsemble(1, bookie1).build(); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md1, bookie1), equalTo(true)); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md1, bookie2), equalTo(false)); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md1, bookie3), equalTo(false)); - - LedgerMetadata md2 = newMetadataWithEnsemble(2, bookie1, bookie2) - .newEnsembleEntry(1, Lists.newArrayList(bookie2, bookie3)).build(); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md2, bookie1), equalTo(true)); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md2, bookie2), equalTo(true)); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md2, bookie3), equalTo(true)); - - LedgerMetadata md3 = newMetadataWithEnsemble(3, bookie1, bookie2) - .newEnsembleEntry(1, Lists.newArrayList(bookie2, bookie1)).build(); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md3, bookie1), equalTo(true)); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md3, bookie2), equalTo(true)); - assertThat(DataIntegrityCheckImpl.ensemblesContainBookie(md3, bookie3), equalTo(false)); - } - - @Test - public void testMetadataCacheLoad() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - lm.createLedgerMetadata(id1, metadata1).get(); - lm.createLedgerMetadata(id2, metadata2).get(); - lm.createLedgerMetadata(id3, metadata3).get(); - - Map ledgers = impl.getCachedOrReadMetadata("test").get(); - assertThat(ledgers.keySet(), containsInAnyOrder(id1, id2, id3)); - } - - @Test - public void testFullCheckCacheLoadAndProcessIfEmpty() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id2, metadata2); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3); - - lm.createLedgerMetadata(id1, metadata1).get(); - lm.createLedgerMetadata(id2, metadata2).get(); - lm.createLedgerMetadata(id3, metadata3).get(); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - - impl.runFullCheck().get(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.ledgerExists(id2), equalTo(true)); - assertThat(storage.ledgerExists(id3), equalTo(true)); - } - - @Test - public void testFullCheckCacheLoadAndProcessSomeInLimbo() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newMetadataWithEnsemble(id3, bookie1, bookie3).build(); - LedgerMetadata metadata3closed = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - return Single.just(metadata3closed); - } - }; - - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id2, metadata2); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3closed); - - lm.createLedgerMetadata(id1, metadata1).get(); - lm.createLedgerMetadata(id2, metadata2).get(); - lm.createLedgerMetadata(id3, metadata3).get(); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - storage.setMasterKey(id3, PASSWD); - storage.setLimboState(id3); - assertThat(storage.hasLimboState(id3), equalTo(true)); - - storage.setStorageStateFlag(StorageState.NEEDS_INTEGRITY_CHECK); - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - isIn(storage.getStorageStateFlags())); - - impl.runFullCheck().get(); - - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - not(isIn(storage.getStorageStateFlags()))); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.ledgerExists(id2), equalTo(true)); - assertThat(storage.ledgerExists(id3), equalTo(true)); - assertThat(storage.hasLimboState(id3), equalTo(false)); - } - - @Test - public void testFullCheckInLimboRecoveryFailsFirstTime() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 1000, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 1000, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newMetadataWithEnsemble(id3, bookie1, bookie3).build(); - LedgerMetadata metadata3closed = newClosedMetadataWithEnsemble(id3, 1000, bookie1, bookie3).build(); - - AtomicInteger callCount = new AtomicInteger(0); - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - if (callCount.getAndIncrement() == 0) { - return Single.error(new BKException.BKReadException()); - } else { - return Single.just(metadata3closed); - } - } - }; - - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id2, metadata2); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3closed); - - lm.createLedgerMetadata(id1, metadata1).get(); - lm.createLedgerMetadata(id2, metadata2).get(); - lm.createLedgerMetadata(id3, metadata3).get(); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - storage.setMasterKey(id3, PASSWD); - storage.setLimboState(id3); - assertThat(storage.hasLimboState(id3), equalTo(true)); - - storage.setStorageStateFlag(StorageState.NEEDS_INTEGRITY_CHECK); - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - isIn(storage.getStorageStateFlags())); - - impl.runFullCheck().get(); - - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - isIn(storage.getStorageStateFlags())); - verify(storage, times(1)).flush(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.ledgerExists(id2), equalTo(true)); - assertThat(storage.ledgerExists(id3), equalTo(true)); - assertThat(storage.entryExists(id3, 0), equalTo(false)); - assertThat(storage.hasLimboState(id3), equalTo(true)); - - // run again, second time shouldn't error - impl.runFullCheck().get(); - - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - not(isIn(storage.getStorageStateFlags()))); - verify(storage, times(2)).flush(); - - assertThat(storage.ledgerExists(id3), equalTo(true)); - assertThat(storage.entryExists(id3, 0), equalTo(true)); - assertThat(storage.hasLimboState(id3), equalTo(false)); - } - - @Test - public void testFullCheckInEntryCopyFailsFirstTime() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 100, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 100, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newMetadataWithEnsemble(id3, bookie1, bookie3).build(); - LedgerMetadata metadata3closed = newClosedMetadataWithEnsemble(id3, 100, bookie1, bookie3).build(); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - return Single.just(metadata3closed); - } - }; - - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id2, metadata2); - - lm.createLedgerMetadata(id1, metadata1).get(); - lm.createLedgerMetadata(id2, metadata2).get(); - lm.createLedgerMetadata(id3, metadata3).get(); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - storage.setMasterKey(id3, PASSWD); - storage.setLimboState(id3); - assertThat(storage.hasLimboState(id3), equalTo(true)); - - storage.setStorageStateFlag(StorageState.NEEDS_INTEGRITY_CHECK); - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - isIn(storage.getStorageStateFlags())); - - impl.runFullCheck().get(); - - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - isIn(storage.getStorageStateFlags())); - verify(storage, times(1)).flush(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.ledgerExists(id2), equalTo(true)); - assertThat(storage.ledgerExists(id3), equalTo(true)); - assertThat(storage.entryExists(id3, 0), equalTo(false)); - assertThat(storage.hasLimboState(id3), equalTo(false)); - - // make it possible to recover the ledger by seeding bookie3 - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3closed); - - // run again, second time shouldn't error - impl.runFullCheck().get(); - - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - not(isIn(storage.getStorageStateFlags()))); - verify(storage, times(2)).flush(); - - assertThat(storage.ledgerExists(id3), equalTo(true)); - assertThat(storage.entryExists(id3, 0), equalTo(true)); - assertThat(storage.hasLimboState(id3), equalTo(false)); - } - - - @Test - public void testFullCheckAllInLimboAndMissing() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newMetadataWithEnsemble(id1, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newMetadataWithEnsemble(id2, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newMetadataWithEnsemble(id3, bookie1, bookie3).build(); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()) { - @Override - Single recoverLedger(long ledgerId, String runId) { - return Single.error( - new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } - }; - - lm.createLedgerMetadata(id1, metadata1).get(); - lm.createLedgerMetadata(id2, metadata2).get(); - lm.createLedgerMetadata(id3, metadata3).get(); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - storage.setMasterKey(id1, PASSWD); - storage.setLimboState(id1); - storage.setMasterKey(id2, PASSWD); - storage.setLimboState(id2); - storage.setMasterKey(id3, PASSWD); - storage.setLimboState(id3); - assertThat(storage.hasLimboState(id1), equalTo(true)); - assertThat(storage.hasLimboState(id2), equalTo(true)); - assertThat(storage.hasLimboState(id3), equalTo(true)); - - storage.setStorageStateFlag(StorageState.NEEDS_INTEGRITY_CHECK); - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - isIn(storage.getStorageStateFlags())); - - impl.runFullCheck().get(); - - verify(storage, times(1)).flush(); - - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - not(isIn(storage.getStorageStateFlags()))); - } - - @Test - public void testFullCheckFailFlushRetainsFlag() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerManager lm = new MockLedgerManager(); - ServerConfiguration conf = serverConf(); - AtomicInteger count = new AtomicInteger(0); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public void flush() throws IOException { - if (count.getAndIncrement() == 0) { - throw new IOException("broken flush"); - } - } - }); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - long id1 = 0xdeadL; - long id2 = 0xbedeL; - long id3 = 0xbebeL; - LedgerMetadata metadata1 = newClosedMetadataWithEnsemble(id1, 100, bookie1, bookie2).build(); - LedgerMetadata metadata2 = newClosedMetadataWithEnsemble(id2, 100, bookie1, bookie3).build(); - LedgerMetadata metadata3 = newClosedMetadataWithEnsemble(id3, 100, bookie1, bookie3).build(); - - DataIntegrityCheckImpl impl = new DataIntegrityCheckImpl(bookie1, lm, storage, - copier, - mock(BookKeeperAdmin.class), - Schedulers.io()); - bookieClient.getMockBookies().seedLedgerForBookie(bookie2, id1, metadata1); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id2, metadata2); - bookieClient.getMockBookies().seedLedgerForBookie(bookie3, id3, metadata3); - - lm.createLedgerMetadata(id1, metadata1).get(); - lm.createLedgerMetadata(id2, metadata2).get(); - lm.createLedgerMetadata(id3, metadata3).get(); - - assertThat(storage.ledgerExists(id1), equalTo(false)); - assertThat(storage.ledgerExists(id2), equalTo(false)); - assertThat(storage.ledgerExists(id3), equalTo(false)); - - storage.setStorageStateFlag(StorageState.NEEDS_INTEGRITY_CHECK); - try { - impl.runFullCheck().get(); - Assert.fail("Should have failed on flush"); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(IOException.class)); - } - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - isIn(storage.getStorageStateFlags())); - verify(storage, times(1)).flush(); - - assertThat(storage.ledgerExists(id1), equalTo(true)); - assertThat(storage.ledgerExists(id2), equalTo(true)); - assertThat(storage.ledgerExists(id3), equalTo(true)); - - // run again, second time shouldn't error - impl.runFullCheck().get(); - - assertThat(StorageState.NEEDS_INTEGRITY_CHECK, - not(isIn(storage.getStorageStateFlags()))); - verify(storage, times(2)).flush(); - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityServiceTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityServiceTest.java deleted file mode 100644 index ec9deecfab0..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityServiceTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie.datainteg; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.server.conf.BookieConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for DataIntegrityService. - */ -public class DataIntegrityServiceTest { - private static DataIntegrityService newLowIntervalService(DataIntegrityCheck check) { - return new DataIntegrityService( - new BookieConfiguration(new ServerConfiguration()), - NullStatsLogger.INSTANCE, check) { - @Override - public int interval() { - return 1; - } - @Override - public TimeUnit intervalUnit() { - return TimeUnit.MICROSECONDS; - } - }; - } - - @Test - public void testFullCheckRunsIfRequested() throws Exception { - CompletableFuture promise = new CompletableFuture<>(); - MockDataIntegrityCheck check = new MockDataIntegrityCheck() { - @Override - public boolean needsFullCheck() { - return true; - } - @Override - public CompletableFuture runFullCheck() { - promise.complete(null); - return super.runFullCheck(); - } - }; - DataIntegrityService service = newLowIntervalService(check); - try { - service.start(); - - promise.get(5, TimeUnit.SECONDS); - } finally { - service.stop(); - } - } - - @Test - public void testFullCheckDoesntRunIfNotRequested() throws Exception { - CompletableFuture promise = new CompletableFuture<>(); - MockDataIntegrityCheck check = new MockDataIntegrityCheck() { - @Override - public boolean needsFullCheck() { - return false; - } - @Override - public CompletableFuture runFullCheck() { - promise.complete(null); - return super.runFullCheck(); - } - }; - DataIntegrityService service = newLowIntervalService(check); - try { - service.start(); - - try { - // timeout set very low, so hard to tell if - // it's waiting to run or not running, but it - // should be the latter on any modern machine - promise.get(100, TimeUnit.MILLISECONDS); - Assert.fail("Shouldn't have run"); - } catch (TimeoutException te) { - // expected - } - } finally { - service.stop(); - } - } - - @Test - public void testFullCheckRunsMultipleTimes() throws Exception { - AtomicInteger count = new AtomicInteger(0); - CompletableFuture promise = new CompletableFuture<>(); - MockDataIntegrityCheck check = new MockDataIntegrityCheck() { - @Override - public boolean needsFullCheck() { - return true; - } - @Override - public CompletableFuture runFullCheck() { - if (count.incrementAndGet() == 10) { - promise.complete(null); - } - return super.runFullCheck(); - } - }; - DataIntegrityService service = newLowIntervalService(check); - try { - service.start(); - - promise.get(10, TimeUnit.SECONDS); - } finally { - service.stop(); - } - } - - @Test - public void testRunDontRunThenRunAgain() throws Exception { - AtomicBoolean needsFullCheck = new AtomicBoolean(true); - Semaphore semaphore = new Semaphore(1); - semaphore.acquire(); // increment the count, can only be released by a check - MockDataIntegrityCheck check = new MockDataIntegrityCheck() { - @Override - public boolean needsFullCheck() { - return needsFullCheck.getAndSet(false); - } - @Override - public CompletableFuture runFullCheck() { - semaphore.release(); - return super.runFullCheck(); - } - }; - DataIntegrityService service = newLowIntervalService(check); - try { - service.start(); - - Assert.assertTrue("Check should have run", - semaphore.tryAcquire(10, TimeUnit.SECONDS)); - Assert.assertFalse("Check shouldn't run again", - semaphore.tryAcquire(100, TimeUnit.MILLISECONDS)); - needsFullCheck.set(true); - Assert.assertTrue("Check should run again", - semaphore.tryAcquire(10, TimeUnit.SECONDS)); - } finally { - service.stop(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/EntryCopierTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/EntryCopierTest.java deleted file mode 100644 index 8f692239b9b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/EntryCopierTest.java +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie.datainteg; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyLong; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.MockLedgerStorage; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.MockTicker; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests for EntryCopierImpl. - */ -@SuppressWarnings("deprecation") -public class EntryCopierTest { - private static final Logger log = LoggerFactory.getLogger(EntryCopierTest.class); - private static final BookieId bookie1 = BookieId.parse("bookie1:3181"); - private static final BookieId bookie2 = BookieId.parse("bookie2:3181"); - private static final BookieId bookie3 = BookieId.parse("bookie3:3181"); - private static final BookieId bookie4 = BookieId.parse("bookie4:3181"); - private static final BookieId bookie5 = BookieId.parse("bookie5:3181"); - private static final BookieId bookie6 = BookieId.parse("bookie6:3181"); - - private OrderedExecutor executor = null; - - @Before - public void setup() throws Exception { - executor = OrderedExecutor.newBuilder().numThreads(1).name("test").build(); - } - - @After - public void teardown() throws Exception { - if (executor != null) { - executor.shutdownNow(); - } - } - - @Test - public void testCopyFromAvailable() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - long ledgerId = 0xbeeb; - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(2) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - EntryCopier.Batch batch = copier.newBatch( - ledgerId, metadata); - - CompletableFuture f1 = batch.copyFromAvailable(0); - CompletableFuture f2 = batch.copyFromAvailable(2); - CompletableFuture f3 = batch.copyFromAvailable(4); - CompletableFuture f4 = batch.copyFromAvailable(10); - try { - batch.copyFromAvailable(100); - Assert.fail("Should have given IllegalArgumentException"); - } catch (IllegalArgumentException ie) { - // correct - } - - try { - batch.copyFromAvailable(-1); - Assert.fail("Should have given IllegalArgumentException"); - } catch (IllegalArgumentException ie) { - // correct - } - CompletableFuture.allOf(f1, f2, f3, f4).get(); - - verify(bookieClient, times(1)).readEntry(eq(bookie2), eq(ledgerId), eq(0L), - any(), any(), anyInt(), any()); - verify(bookieClient, times(1)).readEntry(eq(bookie2), eq(ledgerId), eq(2L), - any(), any(), anyInt(), any()); - verify(bookieClient, times(1)).readEntry(eq(bookie2), eq(ledgerId), eq(4L), - any(), any(), anyInt(), any()); - verify(bookieClient, times(1)).readEntry(eq(bookie2), eq(ledgerId), eq(10L), - any(), any(), anyInt(), any()); - verify(bookieClient, times(4)).readEntry(eq(bookie2), eq(ledgerId), anyLong(), - any(), any(), anyInt(), any()); - - verify(storage, times(4)).addEntry(any()); - assertThat(storage.entryExists(ledgerId, 0), equalTo(true)); - assertThat(storage.entryExists(ledgerId, 2), equalTo(true)); - assertThat(storage.entryExists(ledgerId, 4), equalTo(true)); - assertThat(storage.entryExists(ledgerId, 10), equalTo(true)); - } - - @Test - public void testNoCopiesAvailable() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - long ledgerId = 0xbeeb; - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .newEnsembleEntry(0, Lists.newArrayList(bookie1)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - EntryCopier.Batch batch = copier.newBatch( - ledgerId, metadata); - List> futures = Lists.newArrayList(); - for (long l = 0; l < 10; l++) { - futures.add(batch.copyFromAvailable(l)); - } - try { - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(); - Assert.fail("Should have failed"); - } catch (ExecutionException e) { - assertThat(e.getCause(), instanceOf(BKException.BKReadException.class)); - } - } - - @Test - public void testCopyOneEntryFails() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - long ledgerId = 0xbeeb; - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(2) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - bookieClient.setPreReadHook((bookie, ledger, entry) -> { - if (entry == 2L) { - return FutureUtils.exception(new BKException.BKTimeoutException()); - } else { - return CompletableFuture.completedFuture(null); - } - }); - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - EntryCopier.Batch batch = copier.newBatch(ledgerId, metadata); - - CompletableFuture f1 = batch.copyFromAvailable(0); - CompletableFuture f2 = batch.copyFromAvailable(2); - CompletableFuture f3 = batch.copyFromAvailable(4); - CompletableFuture f4 = batch.copyFromAvailable(10); - - try { - CompletableFuture.allOf(f1, f2, f3, f4).get(); - Assert.fail("Should have failed"); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(BKException.BKTimeoutException.class)); - } - - // other entries should still have been added - verify(storage, times(3)).addEntry(any()); - assertThat(storage.entryExists(ledgerId, 0), equalTo(true)); - assertThat(storage.entryExists(ledgerId, 4), equalTo(true)); - assertThat(storage.entryExists(ledgerId, 10), equalTo(true)); - } - - @Test - public void testCopyAllEntriesFail() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerStorage storage = spy(new MockLedgerStorage()); - long ledgerId = 0xbeeb; - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(2) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - bookieClient.setPreReadHook((bookie, ledger, entry) -> - FutureUtils.exception(new BKException.BKTimeoutException())); - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - EntryCopier.Batch batch = copier.newBatch(ledgerId, metadata); - - CompletableFuture f1 = batch.copyFromAvailable(0); - CompletableFuture f2 = batch.copyFromAvailable(2); - CompletableFuture f3 = batch.copyFromAvailable(4); - CompletableFuture f4 = batch.copyFromAvailable(10); - - try { - CompletableFuture.allOf(f1, f2, f3, f4).get(); - Assert.fail("Should have failed"); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(BKException.BKTimeoutException.class)); - } - - // Nothing should have been added - verify(storage, times(0)).addEntry(any()); - } - - @Test - public void testCopyOneEntryFailsOnStorage() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public long addEntry(ByteBuf buffer) throws IOException, BookieException { - long entryId = buffer.getLong(buffer.readerIndex() + 8); - if (entryId == 0L) { - throw new IOException("failing"); - } - return super.addEntry(buffer); - } - }); - long ledgerId = 0xbeeb; - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(2) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - EntryCopier.Batch batch = copier.newBatch(ledgerId, metadata); - - CompletableFuture f1 = batch.copyFromAvailable(0); - CompletableFuture f2 = batch.copyFromAvailable(2); - CompletableFuture f3 = batch.copyFromAvailable(4); - CompletableFuture f4 = batch.copyFromAvailable(10); - - try { - CompletableFuture.allOf(f1, f2, f3, f4).get(); - Assert.fail("Should have failed"); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(IOException.class)); - } - - // other entries should still have been added - verify(storage, times(4)).addEntry(any()); - assertThat(storage.entryExists(ledgerId, 0), equalTo(false)); - assertThat(storage.entryExists(ledgerId, 2), equalTo(true)); - assertThat(storage.entryExists(ledgerId, 4), equalTo(true)); - assertThat(storage.entryExists(ledgerId, 10), equalTo(true)); - } - - @Test - public void testCopyAllEntriesFailOnStorage() throws Exception { - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - MockLedgerStorage storage = spy(new MockLedgerStorage() { - @Override - public long addEntry(ByteBuf buffer) throws IOException, BookieException { - throw new IOException("failing"); - } - }); - long ledgerId = 0xbeeb; - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(2) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - EntryCopier copier = new EntryCopierImpl(bookie1, bookieClient, storage, new MockTicker()); - EntryCopier.Batch batch = copier.newBatch(ledgerId, metadata); - - CompletableFuture f1 = batch.copyFromAvailable(0); - CompletableFuture f2 = batch.copyFromAvailable(2); - CompletableFuture f3 = batch.copyFromAvailable(4); - CompletableFuture f4 = batch.copyFromAvailable(10); - - try { - CompletableFuture.allOf(f1, f2, f3, f4).get(); - Assert.fail("Should have failed"); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(IOException.class)); - } - - // other entries should still have been added - verify(storage, times(4)).addEntry(any()); - assertThat(storage.entryExists(ledgerId, 0), equalTo(false)); - assertThat(storage.entryExists(ledgerId, 2), equalTo(false)); - assertThat(storage.entryExists(ledgerId, 4), equalTo(false)); - assertThat(storage.entryExists(ledgerId, 10), equalTo(false)); - } - - @Test - public void testReadOneEntry() throws Exception { - long ledgerId = 0xbeeb; // don't change, the shuffle for preferred bookies uses ledger id as seed - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(3) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2, bookie3)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - EntryCopier copier = new EntryCopierImpl(bookie2, bookieClient, - new MockLedgerStorage(), new MockTicker()); - EntryCopierImpl.BatchImpl batch = (EntryCopierImpl.BatchImpl) copier.newBatch(ledgerId, metadata); - for (int i = 0; i <= 10; i++) { - batch.fetchEntry(i).get(); - verify(bookieClient, times(i + 1)).readEntry(any(), anyLong(), anyLong(), - any(), any(), anyInt()); - verify(bookieClient, times(i + 1)).readEntry(eq(bookie3), anyLong(), anyLong(), - any(), any(), anyInt()); - } - } - - @Test - public void testReadOneFirstReplicaFails() throws Exception { - long ledgerId = 0xbeeb; // don't change, the shuffle for preferred bookies uses ledger id as seed - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(3) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2, bookie3)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - bookieClient.errorBookies(bookie3); - MockTicker ticker = new MockTicker(); - EntryCopierImpl copier = new EntryCopierImpl(bookie2, bookieClient, - new MockLedgerStorage(), ticker); - CompletableFuture errorProcessedPromise = new CompletableFuture<>(); - EntryCopierImpl.BatchImpl batch = copier.new BatchImpl(bookie2, ledgerId, - metadata, - new EntryCopierImpl.SinBin(ticker)) { - @Override - void notifyBookieError(BookieId bookie) { - super.notifyBookieError(bookie); - errorProcessedPromise.complete(null); - } - }; - - batch.fetchEntry(0).get(); - - // will read twice, fail at bookie3, succeed at bookie1 - verify(bookieClient, times(2)).readEntry(any(), anyLong(), anyLong(), - any(), any(), anyInt()); - verify(bookieClient, times(1)).readEntry(eq(bookie3), anyLong(), anyLong(), - any(), any(), anyInt()); - verify(bookieClient, times(1)).readEntry(eq(bookie1), anyLong(), anyLong(), - any(), any(), anyInt()); - errorProcessedPromise.get(10, TimeUnit.SECONDS); - batch.fetchEntry(1).get(); - - // subsequent read should go straight for bookie1 - verify(bookieClient, times(3)).readEntry(any(), anyLong(), anyLong(), - any(), any(), anyInt()); - verify(bookieClient, times(2)).readEntry(eq(bookie1), anyLong(), anyLong(), - any(), any(), anyInt()); - } - - @Test - public void testReadOneAllReplicasFail() throws Exception { - long ledgerId = 0xbeeb; // don't change, the shuffle for preferred bookies uses ledger id as seed - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(3) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2, bookie3)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - // we expect to try to read from bookie3 first - bookieClient.setPreReadHook((bookie, ledgerId1, entryId) -> { - if (bookie.equals(bookie1)) { - return FutureUtils.exception(new BKException.BKReadException()); - } else if (bookie.equals(bookie3)) { - return FutureUtils.exception(new BKException.BKBookieException()); - } else { - return CompletableFuture.completedFuture(null); - } - }); - EntryCopier copier = new EntryCopierImpl(bookie2, bookieClient, - new MockLedgerStorage(), new MockTicker()); - EntryCopierImpl.BatchImpl batch = (EntryCopierImpl.BatchImpl) copier.newBatch(ledgerId, metadata); - - try { - batch.fetchEntry(0).get(); - Assert.fail("Shouldn't get this far"); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(BKException.BKBookieException.class)); - } - - InOrder inOrder = inOrder(bookieClient); - inOrder.verify(bookieClient, times(1)).readEntry(eq(bookie3), anyLong(), anyLong(), - any(), any(), anyInt()); - inOrder.verify(bookieClient, times(1)).readEntry(eq(bookie1), anyLong(), anyLong(), - any(), any(), anyInt()); - } - - @Test - public void testReadOneWithErrorBookieReinstatedAfterSinBin() throws Exception { - long ledgerId = 0xbeeb; // don't change, the shuffle for preferred bookies uses ledger id as seed - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(3) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2, bookie3)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - bookieClient.errorBookies(bookie3); - - CompletableFuture errorProcessedPromise = new CompletableFuture<>(); - - MockTicker ticker = new MockTicker(); - EntryCopierImpl copier = new EntryCopierImpl(bookie2, bookieClient, - new MockLedgerStorage(), ticker); - EntryCopierImpl.SinBin sinBin = new EntryCopierImpl.SinBin(ticker); - EntryCopierImpl.BatchImpl batch = copier.new BatchImpl(bookie2, ledgerId, metadata, sinBin) { - @Override - void notifyBookieError(BookieId bookie) { - super.notifyBookieError(bookie); - errorProcessedPromise.complete(null); - } - }; - batch.fetchEntry(0).get(); - verify(bookieClient, times(1)).readEntry(eq(bookie3), anyLong(), anyLong(), - any(), any(), anyInt()); - verify(bookieClient, times(1)).readEntry(eq(bookie1), anyLong(), anyLong(), - any(), any(), anyInt()); - errorProcessedPromise.get(10, TimeUnit.SECONDS); - - // bookie3 should be fine to use again, but we shouldn't use it until if come out - // of the sinbin - bookieClient.removeErrors(bookie3); - - // read batch again, error should carry over - EntryCopierImpl.BatchImpl batch2 = copier.new BatchImpl(bookie2, ledgerId, metadata, sinBin); - batch2.fetchEntry(0).get(); - verify(bookieClient, times(1)).readEntry(eq(bookie3), anyLong(), anyLong(), - any(), any(), anyInt()); - verify(bookieClient, times(2)).readEntry(eq(bookie1), anyLong(), anyLong(), - any(), any(), anyInt()); - // advance time - ticker.advance(70, TimeUnit.SECONDS); - - // sinbinned bookie should be restored, read should come from bookie3 again - EntryCopierImpl.BatchImpl batch3 = copier.new BatchImpl(bookie2, ledgerId, metadata, sinBin); - batch3.fetchEntry(0).get(); - verify(bookieClient, times(2)).readEntry(eq(bookie3), anyLong(), anyLong(), - any(), any(), anyInt()); - verify(bookieClient, times(2)).readEntry(eq(bookie1), anyLong(), anyLong(), - any(), any(), anyInt()); - } - - @Test - public void testReadEntryOnlyOnSelf() throws Exception { - long ledgerId = 0xbeeb; - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .newEnsembleEntry(0, Lists.newArrayList(bookie2)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - - MockBookieClient bookieClient = spy(new MockBookieClient(executor)); - bookieClient.getMockBookies().seedLedger(ledgerId, metadata); - - CompletableFuture errorProcessedPromise = new CompletableFuture<>(); - - MockTicker ticker = new MockTicker(); - EntryCopierImpl copier = new EntryCopierImpl(bookie2, bookieClient, - new MockLedgerStorage(), ticker); - EntryCopierImpl.BatchImpl batch = (EntryCopierImpl.BatchImpl) copier.newBatch(ledgerId, metadata); - try { - batch.fetchEntry(0).get(); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(BKException.BKReadException.class)); - } - verify(bookieClient, times(0)).readEntry(any(), anyLong(), anyLong(), - any(), any(), anyInt()); - } - - @Test - public void testPreferredBookieIndices() throws Exception { - long ledgerId = 0xbeeb; - LedgerMetadata metadata1 = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(5) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0, Lists.newArrayList(bookie1, bookie2, bookie3, bookie4, bookie5)) - .newEnsembleEntry(3, Lists.newArrayList(bookie1, bookie6, bookie3, bookie4, bookie5)) - .newEnsembleEntry(5, Lists.newArrayList(bookie1, bookie2, bookie3, bookie4, bookie5)) - .withLastEntryId(10) - .withLength(1000) - .withClosedState() - .build(); - - Map> order = - EntryCopierImpl.preferredBookieIndices(bookie2, metadata1, - Collections.emptySet(), - ledgerId); - assertThat(order.get(0L), contains(4, 0, 3, 2)); - assertThat(order.get(3L), contains(4, 1, 0, 3, 2)); - assertThat(order.get(5L), contains(4, 0, 3, 2)); - - Map> orderWithErr = - EntryCopierImpl.preferredBookieIndices(bookie2, metadata1, - Sets.newHashSet(bookie1, bookie3), - ledgerId); - assertThat(orderWithErr.get(0L), contains(4, 3, 0, 2)); - assertThat(orderWithErr.get(3L), contains(4, 1, 3, 0, 2)); - assertThat(orderWithErr.get(5L), contains(4, 3, 0, 2)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MetadataAsyncIteratorTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MetadataAsyncIteratorTest.java deleted file mode 100644 index 32f7c846f9b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MetadataAsyncIteratorTest.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie.datainteg; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; - -import com.google.common.collect.Lists; -import io.reactivex.rxjava3.schedulers.Schedulers; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.MockLedgerManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests for MetadataAsyncIterator. - */ -public class MetadataAsyncIteratorTest { - private static Logger log = LoggerFactory.getLogger(MetadataAsyncIteratorTest.class); - - private LedgerMetadata newRandomMetadata(long randBit) throws Exception { - return LedgerMetadataBuilder.create() - .withId(1) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32C) - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .newEnsembleEntry(0, Lists.newArrayList( - BookieId.parse("foobar-" + randBit + ":3181"))) - .build(); - } - - private ConcurrentHashMap addLedgers(LedgerManager lm, int count) - throws Exception { - ConcurrentHashMap added = new ConcurrentHashMap<>(); - for (long i = 0; i < count; i++) { - LedgerMetadata metadata = newRandomMetadata(i); - lm.createLedgerMetadata(i, metadata).get(); - added.put(i, metadata); - } - return added; - } - - private static CompletableFuture removeFromMap( - ConcurrentHashMap map, - long ledgerId, LedgerMetadata metadata) { - if (log.isDebugEnabled()) { - log.debug("removing ledger {}", ledgerId); - } - if (map.remove(ledgerId, metadata)) { - return CompletableFuture.completedFuture(null); - } else { - if (log.isDebugEnabled()) { - log.debug("ledger {} already removed", ledgerId); - } - return FutureUtils.exception(new Exception("ledger already removed")); - } - } - - @Test - public void testIteratorOverAll() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ConcurrentHashMap added = addLedgers(lm, 10000); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - iterator.forEach((ledgerId, metadata) -> removeFromMap(added, ledgerId, metadata)) - .get(10, TimeUnit.SECONDS); - assertThat(added.isEmpty(), equalTo(true)); - } - - @Test - public void testSingleLedger() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - LedgerMetadata single = newRandomMetadata(0xdeadbeef); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - iterator.forEach((ledgerId, metadata) -> { - if (ledgerId == 0xdeadbeef && metadata.equals(single)) { - return CompletableFuture.completedFuture(null); - } else { - return FutureUtils.exception(new Exception("Unexpected metadata")); - } - }).get(10, TimeUnit.SECONDS); - } - - @Test - public void testEmptyRange() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - iterator.forEach((ledgerId, metadata) -> FutureUtils.exception(new Exception("Should be empty"))) - .get(10, TimeUnit.SECONDS); - } - - @Test - public void testOneLedgerErrorsOnRead() throws Exception { - MockLedgerManager lm = new MockLedgerManager() { - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - if (ledgerId == 403) { - return FutureUtils.exception(new BKException.ZKException()); - } else { - return super.readLedgerMetadata(ledgerId); - } - } - }; - ConcurrentHashMap added = addLedgers(lm, 10000); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - try { - iterator.forEach((ledgerId, metadata) -> removeFromMap(added, ledgerId, metadata)) - .get(10, TimeUnit.SECONDS); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(BKException.ZKException.class)); - } - } - - @Test - public void testOneLedgerErrorsOnProcessing() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ConcurrentHashMap added = addLedgers(lm, 10000); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - try { - iterator.forEach((ledgerId, metadata) -> { - if (ledgerId == 403) { - log.info("IKDEBUG erroring"); - return FutureUtils.exception(new Exception("foobar")); - } else { - return CompletableFuture.completedFuture(null); - } - }).get(10, TimeUnit.SECONDS); - Assert.fail("shouldn't succeed"); - } catch (ExecutionException ee) { - assertThat(ee.getCause().getMessage(), equalTo("foobar")); - } - } - - @Test - public void testAllLedgersErrorOnRead() throws Exception { - MockLedgerManager lm = new MockLedgerManager() { - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - CompletableFuture> promise = new CompletableFuture<>(); - promise.completeExceptionally(new BKException.ZKException()); - return promise; - } - }; - ConcurrentHashMap added = addLedgers(lm, 10000); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - try { - iterator.forEach((ledgerId, metadata) -> CompletableFuture.completedFuture(null)) - .get(10, TimeUnit.SECONDS); - } catch (ExecutionException ee) { - assertThat(ee.getCause(), instanceOf(BKException.ZKException.class)); - } - } - - @Test - public void testAllLedgersErrorOnProcessing() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - ConcurrentHashMap added = addLedgers(lm, 10000); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - try { - iterator.forEach((ledgerId, metadata) -> FutureUtils.exception(new Exception("foobar"))) - .get(10, TimeUnit.SECONDS); - Assert.fail("shouldn't succeed"); - } catch (ExecutionException ee) { - assertThat(ee.getCause().getMessage(), equalTo("foobar")); - } - } - - @Test - public void testOneLedgerDisappearsBetweenListAndRead() throws Exception { - MockLedgerManager lm = new MockLedgerManager() { - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - if (ledgerId == 501) { - CompletableFuture> promise = new CompletableFuture<>(); - promise.completeExceptionally(new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - return promise; - } else { - return super.readLedgerMetadata(ledgerId); - } - } - }; - ConcurrentHashMap added = addLedgers(lm, 10000); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100 /* inflight */, - 3 /* timeout */, TimeUnit.SECONDS); - iterator.forEach((ledgerId, metadata) -> removeFromMap(added, ledgerId, metadata)) - .get(10, TimeUnit.SECONDS); - assertThat(added.size(), equalTo(1)); - log.info("IKDEBUG {} {}", added, added.containsKey(5L)); - assertThat(added.containsKey(501L), equalTo(true)); - } - - @Test - public void testEverySecondLedgerDisappearsBetweenListAndRead() throws Exception { - MockLedgerManager lm = new MockLedgerManager() { - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - if (ledgerId % 2 == 0) { - return FutureUtils.exception( - new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } else { - return super.readLedgerMetadata(ledgerId); - } - } - }; - int numLedgers = 10000; - ConcurrentHashMap added = addLedgers(lm, numLedgers); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100, - 3, TimeUnit.SECONDS); - iterator.forEach((ledgerId, metadata) -> removeFromMap(added, ledgerId, metadata)) - .get(10, TimeUnit.SECONDS); - assertThat(added.size(), equalTo(numLedgers / 2)); - assertThat(added.keySet().stream().allMatch(k -> k % 2 == 0), equalTo(true)); - assertThat(added.keySet().stream().noneMatch(k -> k % 2 == 1), equalTo(true)); - } - - @Test - public void testEveryLedgerDisappearsBetweenListAndRead() throws Exception { - MockLedgerManager lm = new MockLedgerManager() { - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - return FutureUtils.exception( - new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } - }; - int numLedgers = 10000; - ConcurrentHashMap added = addLedgers(lm, numLedgers); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 100, - 3, TimeUnit.SECONDS); - iterator.forEach((ledgerId, metadata) -> removeFromMap(added, ledgerId, metadata)) - .get(10, TimeUnit.SECONDS); - assertThat(added.size(), equalTo(numLedgers)); - } - - @Test - public void testMaxOutInFlight() throws Exception { - MockLedgerManager lm = new MockLedgerManager(); - int numLedgers = 1000; - ConcurrentHashMap added = addLedgers(lm, numLedgers); - MetadataAsyncIterator iterator = new MetadataAsyncIterator(Schedulers.io(), - lm, 10, - 3, TimeUnit.SECONDS); - CompletableFuture blocker = new CompletableFuture<>(); - CompletableFuture iterFuture = iterator.forEach( - (ledgerId, metadata) -> - blocker.thenCompose(ignore -> removeFromMap(added, ledgerId, metadata))); - assertThat(iterFuture.isDone(), equalTo(false)); - blocker.complete(null); - iterFuture.get(10, TimeUnit.SECONDS); - assertThat(added.isEmpty(), equalTo(true)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MockDataIntegrityCheck.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MockDataIntegrityCheck.java deleted file mode 100644 index cfbb1b17660..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MockDataIntegrityCheck.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie.datainteg; - -import java.util.concurrent.CompletableFuture; - -/** - * Mock implementation of MockDataIntegrity. - */ -public class MockDataIntegrityCheck implements DataIntegrityCheck { - @Override - public CompletableFuture runPreBootCheck(String reason) { - return CompletableFuture.completedFuture(null); - } - @Override - public boolean needsFullCheck() { - return false; - } - @Override - public CompletableFuture runFullCheck() { - return CompletableFuture.completedFuture(null); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/WriteSetsTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/WriteSetsTest.java deleted file mode 100644 index 49a121ec5b2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/WriteSetsTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.bookie.datainteg; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.ImmutableList; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import org.apache.bookkeeper.client.DistributionSchedule; -import org.apache.bookkeeper.client.RoundRobinDistributionSchedule; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests for WriteSets. - */ -public class WriteSetsTest { - private static final Logger log = LoggerFactory.getLogger(WriteSetsTest.class); - - @Test - public void testOrderPreserved() throws Exception { - WriteSets writeSets = new WriteSets(ImmutableList.of(0, 3, 2, 4, 1), - 5 /* ensemble */, 2 /* writeQ */); - assertThat(writeSets.getForEntry(0), contains(0, 1)); - assertThat(writeSets.getForEntry(1), contains(2, 1)); - assertThat(writeSets.getForEntry(2), contains(3, 2)); - assertThat(writeSets.getForEntry(3), contains(3, 4)); - assertThat(writeSets.getForEntry(4), contains(0, 4)); - } - - @Test - public void testOrderPreservedWithGapForCurrentBookie() throws Exception { - // my bookie id maps to 2, so it is missing from the preferred order - WriteSets writeSets = new WriteSets(ImmutableList.of(0, 3, 4, 1), - 5 /* ensemble */, 2 /* writeQ */); - assertThat(writeSets.getForEntry(0), contains(0, 1)); - assertThat(writeSets.getForEntry(1), contains(1)); - assertThat(writeSets.getForEntry(2), contains(3)); - assertThat(writeSets.getForEntry(3), contains(3, 4)); - assertThat(writeSets.getForEntry(4), contains(0, 4)); - } - - @Test - public void testEmptyWriteSet() throws Exception { - // As can happen if we are the only bookie for a entry - WriteSets writeSets = new WriteSets(ImmutableList.of(0, 3, 4, 1), - 5 /* ensemble */, 1 /* writeQ */); - assertThat(writeSets.getForEntry(0), contains(0)); - assertThat(writeSets.getForEntry(1), contains(1)); - assertThat(writeSets.getForEntry(2), empty()); - assertThat(writeSets.getForEntry(3), contains(3)); - assertThat(writeSets.getForEntry(4), contains(4)); - } - - @Test - public void testE2W2() throws Exception { - DistributionSchedule schedule = new RoundRobinDistributionSchedule( - 2 /* write */, 2 /* ack */, 2 /* ensemble */); - WriteSets writeSets = new WriteSets(ImmutableList.of(0, 1), - 2 /* ensemble */, 2 /* writeQ */); - for (int i = 0; i < 100; i++) { - ImmutableList writeSet = writeSets.getForEntry(i); - DistributionSchedule.WriteSet distWriteSet = schedule.getWriteSet(i); - assertContentsMatch(writeSet, distWriteSet); - } - - WriteSets writeSets2 = new WriteSets(ImmutableList.of(1, 0), - 2 /* ensemble */, 2 /* writeQ */); - for (int i = 0; i < 100; i++) { - ImmutableList writeSet = writeSets2.getForEntry(i); - DistributionSchedule.WriteSet distWriteSet = schedule.getWriteSet(i); - assertContentsMatch(writeSet, distWriteSet); - } - }; - - @Test - public void testE10W2() throws Exception { - DistributionSchedule schedule = new RoundRobinDistributionSchedule( - 2 /* write */, 2 /* ack */, 10 /* ensemble */); - WriteSets writeSets = new WriteSets(ImmutableList.of(0, 8, 1, 9, 6, 3, 7, 4, 2, 5), - 10 /* ensemble */, - 2 /* writeQ */); - for (int i = 0; i < 100; i++) { - ImmutableList writeSet = writeSets.getForEntry(i); - DistributionSchedule.WriteSet distWriteSet = schedule.getWriteSet(i); - assertContentsMatch(writeSet, distWriteSet); - } - - WriteSets writeSets2 = new WriteSets(ImmutableList.of(7, 5, 1, 6, 3, 0, 8, 9, 4, 2), - 10 /* ensemble */, - 2 /* writeQ */); - for (int i = 0; i < 100; i++) { - ImmutableList writeSet = writeSets2.getForEntry(i); - DistributionSchedule.WriteSet distWriteSet = schedule.getWriteSet(i); - assertContentsMatch(writeSet, distWriteSet); - } - - WriteSets writeSets3 = new WriteSets(ImmutableList.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), - 10 /* ensemble */, - 2 /* writeQ */); - for (int i = 0; i < 100; i++) { - ImmutableList writeSet = writeSets3.getForEntry(i); - DistributionSchedule.WriteSet distWriteSet = schedule.getWriteSet(i); - assertContentsMatch(writeSet, distWriteSet); - } - }; - - @Test - public void testManyVariants() throws Exception { - for (int w = 1; w <= 12; w++) { - for (int e = w; e <= 12; e++) { - DistributionSchedule schedule = new RoundRobinDistributionSchedule( - w /* write */, w /* ack */, e /* ensemble */); - - // Create shuffled set of indices - List indices = new ArrayList<>(); - for (int i = 0; i < e; i++) { - indices.add(i); - } - Collections.shuffle(indices); - - WriteSets writeSets = new WriteSets(ImmutableList.copyOf(indices), - e, w); - for (int i = 0; i < 100; i++) { - ImmutableList writeSet = writeSets.getForEntry(i); - DistributionSchedule.WriteSet distWriteSet = schedule.getWriteSet(i); - assertContentsMatch(writeSet, distWriteSet); - } - } - } - } - - @SuppressWarnings("deprecation") - private static void assertContentsMatch(ImmutableList writeSet, - DistributionSchedule.WriteSet distWriteSet) - throws Exception { - log.info("writeSet {} distWriteSet {}", writeSet, distWriteSet.size()); - assertThat(writeSet.size(), equalTo(distWriteSet.size())); - for (Integer i : writeSet) { - assertThat(distWriteSet.contains(i), equalTo(true)); - } - - for (int i = 0; i < distWriteSet.size(); i++) { - assertTrue(writeSet.contains(distWriteSet.get(i))); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/EntryLogTestUtils.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/EntryLogTestUtils.java deleted file mode 100644 index f88e3883af5..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/EntryLogTestUtils.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import com.google.common.util.concurrent.MoreExecutors; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.util.Arrays; -import org.apache.bookkeeper.bookie.DefaultEntryLogger; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.storage.directentrylogger.DirectEntryLogger; -import org.apache.bookkeeper.bookie.storage.directentrylogger.EntryLogIdsImpl; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.DiskChecker; - -/** - * EntryLogTestUtils. - */ -public class EntryLogTestUtils { - private static final Slogger slog = Slogger.CONSOLE; - - public static LedgerDirsManager newDirsManager(File... ledgerDir) throws Exception { - return new LedgerDirsManager( - new ServerConfiguration(), ledgerDir, new DiskChecker(0.999f, 0.999f)); - } - - public static EntryLogger newLegacyEntryLogger(int logSizeLimit, File... ledgerDir) throws Exception { - ServerConfiguration conf = new ServerConfiguration(); - conf.setEntryLogSizeLimit(logSizeLimit); - return new DefaultEntryLogger(conf, newDirsManager(ledgerDir), null, - NullStatsLogger.INSTANCE, ByteBufAllocator.DEFAULT); - } - - public static DirectEntryLogger newDirectEntryLogger(int logSizeLimit, File ledgerDir) throws Exception { - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - return new DirectEntryLogger( - curDir, new EntryLogIdsImpl(newDirsManager(ledgerDir), slog), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - logSizeLimit, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE); - } - - public static int logIdFromLocation(long location) { - return (int) (location >> 32); - } - - public static ByteBuf makeEntry(long ledgerId, long entryId, int size) { - return makeEntry(ledgerId, entryId, size, (byte) 0xdd); - } - - public static ByteBuf makeEntry(long ledgerId, long entryId, int size, byte pattern) { - ByteBuf buf = Unpooled.buffer(size); - buf.writeLong(ledgerId).writeLong(entryId); - byte[] data = new byte[buf.writableBytes()]; - Arrays.fill(data, pattern); - buf.writeBytes(data); - return buf; - } - - public static void assertEntryEquals(ByteBuf e1, ByteBuf e2) throws Exception { - assertThat(e1.readableBytes(), equalTo(e2.readableBytes())); - assertThat(e1, equalTo(e2)); - } - -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/MockEntryLogIds.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/MockEntryLogIds.java deleted file mode 100644 index 2f9e7bca2ec..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/MockEntryLogIds.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * MockEntryLogIds. - */ -public class MockEntryLogIds implements EntryLogIds { - private final AtomicInteger counter = new AtomicInteger(0); - @Override - public int nextId() { - return counter.incrementAndGet(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestBuffer.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestBuffer.java deleted file mode 100644 index a4d9554166c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestBuffer.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -// CHECKSTYLE.OFF: IllegalImport -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.util.internal.PlatformDependent; -import java.io.IOException; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.junit.Test; -// CHECKSTYLE.ON: IllegalImport - -/** - * TestBuffer. - */ -public class TestBuffer { - - @Test - public void testIsAligned() throws Exception { - assertFalse(Buffer.isAligned(1234)); - assertTrue(Buffer.isAligned(4096)); - assertTrue(Buffer.isAligned(40960)); - assertTrue(Buffer.isAligned(1 << 20)); - assertFalse(Buffer.isAligned(-1)); - assertFalse(Buffer.isAligned(Integer.MAX_VALUE)); - assertFalse(Buffer.isAligned(Integer.MIN_VALUE)); - } - - @Test - public void testNextAlignment() throws Exception { - assertEquals(0, Buffer.nextAlignment(0)); - assertEquals(4096, Buffer.nextAlignment(1)); - assertEquals(4096, Buffer.nextAlignment(4096)); - assertEquals(8192, Buffer.nextAlignment(4097)); - assertEquals(0x7FFFF000, Buffer.nextAlignment(0x7FFFF000)); - } - - @Test(expected = IllegalArgumentException.class) - public void testNegativePosition() throws Exception { - Buffer.nextAlignment(-1); - } - - @Test(expected = IllegalArgumentException.class) - public void testMaxAlignment() throws Exception { - Buffer.nextAlignment(Integer.MAX_VALUE); - } - - @Test(expected = IllegalArgumentException.class) - public void testCreateUnaligned() throws Exception { - new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1234); - } - - @Test - public void testWriteInt() throws Exception { - int bufferSize = 1 << 20; - Buffer b = new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, bufferSize); - assertTrue(b.hasSpace(bufferSize)); - assertEquals(0, b.position()); - b.writeInt(0xdeadbeef); - - - assertEquals((byte) 0xde, PlatformDependent.getByte(b.pointer() + 0)); - assertEquals((byte) 0xad, PlatformDependent.getByte(b.pointer() + 1)); - assertEquals((byte) 0xbe, PlatformDependent.getByte(b.pointer() + 2)); - assertEquals((byte) 0xef, PlatformDependent.getByte(b.pointer() + 3)); - - assertFalse(b.hasSpace(bufferSize)); - assertEquals(Integer.BYTES, b.position()); - - for (int i = 0; i < 10000; i++) { - b.writeInt(i); - } - assertEquals(Integer.BYTES * 10001, b.position()); - assertTrue(b.hasSpace(bufferSize - (Integer.BYTES * 10001))); - assertFalse(b.hasSpace(bufferSize - (Integer.BYTES * 10000))); - - assertEquals(0xdeadbeef, b.readInt(0)); - for (int i = 0; i < 10000; i++) { - assertEquals(i, b.readInt((i + 1) * Integer.BYTES)); - } - b.reset(); - assertTrue(b.hasSpace(bufferSize)); - assertEquals(0, b.position()); - } - - @Test - public void testWriteBuffer() throws Exception { - ByteBuf bb = Unpooled.buffer(1021); - fillByteBuf(bb, 0xdeadbeef); - int bufferSize = 1 << 20; - Buffer b = new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, bufferSize); - assertEquals(0, b.position()); - b.writeByteBuf(bb); - assertEquals(1021, b.position()); - assertEquals(0, bb.readableBytes()); - bb.clear(); - fillByteBuf(bb, 0xcafecafe); - b.writeByteBuf(bb); - assertEquals(0, bb.readableBytes()); - assertEquals(2042, b.position()); - - bb = Unpooled.buffer(2042); - int ret = b.readByteBuf(bb, 0, 2042); - assertEquals(2042, ret); - for (int i = 0; i < 1020 / Integer.BYTES; i++) { - assertEquals(0xdeadbeef, bb.readInt()); - } - assertEquals((byte) 0xde, bb.readByte()); - for (int i = 0; i < 1020 / Integer.BYTES; i++) { - assertEquals(0xcafecafe, bb.readInt()); - } - } - - @Test - public void testPartialRead() throws Exception { - ByteBuf bb = Unpooled.buffer(5000); - - Buffer b = new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 4096); - for (int i = 0; i < 4096 / Integer.BYTES; i++) { - b.writeInt(0xdeadbeef); - } - - int ret = b.readByteBuf(bb, 0, 5000); - assertEquals(4096, ret); - } - - @Test(expected = IOException.class) - public void testReadIntAtBoundary() throws Exception { - Buffer b = new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 4096); - - for (int i = 0; i < 4096 / Integer.BYTES; i++) { - b.writeInt(0xdeadbeef); - } - assertTrue(b.hasData(4092, Integer.BYTES)); - assertFalse(b.hasData(4093, Integer.BYTES)); - assertFalse(b.hasData(4096, Integer.BYTES)); - - b.readInt(4096 - 2); - } - - @Test(expected = IOException.class) - public void testReadLongAtBoundary() throws Exception { - Buffer b = new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 4096); - - for (int i = 0; i < 4096 / Integer.BYTES; i++) { - b.writeInt(0xdeadbeef); - } - assertTrue(b.hasData(4088, Long.BYTES)); - assertFalse(b.hasData(4089, Long.BYTES)); - assertFalse(b.hasData(4096, Long.BYTES)); - - b.readInt(4096 - 2); - } - - @Test - public void testPadToAlignment() throws Exception { - Buffer b = new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 23); - - for (int i = 0; i < 1025; i++) { - b.writeInt(0xdededede); - } - int writtenLength = b.padToAlignment(); - - assertEquals(8192, writtenLength); - assertEquals(0xdededede, b.readInt(1024 * Integer.BYTES)); - for (int i = 1025 * Integer.BYTES; i < writtenLength; i += Integer.BYTES) { - assertEquals(0xf0f0f0f0, b.readInt(i)); - } - assertEquals(0, b.readInt(writtenLength)); - } - - @Test - public void testFree() throws Exception { - Buffer b = new Buffer(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 23); - b.free(); // success if process doesn't explode - b.free(); - } - - static void fillByteBuf(ByteBuf bb, int value) { - while (bb.writableBytes() >= Integer.BYTES) { - bb.writeInt(value); - } - for (int i = 0; i < Integer.BYTES && bb.writableBytes() > 0; i++) { - byte b = (byte) (value >> (Integer.BYTES - i - 1) * 8); - bb.writeByte(b); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLogger.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLogger.java deleted file mode 100644 index 73ae500a77c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLogger.java +++ /dev/null @@ -1,518 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.assertEntryEquals; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.logIdFromLocation; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.makeEntry; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; - -import com.google.common.util.concurrent.MoreExecutors; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.util.ReferenceCountUtil; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.EntryLogMetadata; -import org.apache.bookkeeper.bookie.storage.EntryLogger; -import org.apache.bookkeeper.bookie.storage.MockEntryLogIds; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - -/** - * TestDirectEntryLogger. - */ -@Slf4j -public class TestDirectEntryLogger { - private final Slogger slog = Slogger.CONSOLE; - - private static final long ledgerId1 = 1234; - - private final TmpDirs tmpDirs = new TmpDirs(); - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - } - - @Test - public void testLogRolling() throws Exception { - File ledgerDir = tmpDirs.createNew("logRolling", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 4000); - ByteBuf e2 = makeEntry(ledgerId1, 2L, 4000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 4000); - - try (EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 9000, // max file size (header + size of one entry) - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - long loc1 = elog.addEntry(ledgerId1, e1.slice()); - int logId1 = logIdFromLocation(loc1); - assertThat(logId1, equalTo(1)); - - long loc2 = elog.addEntry(ledgerId1, e2.slice()); - int logId2 = logIdFromLocation(loc2); - assertThat(logId2, equalTo(2)); - - long loc3 = elog.addEntry(ledgerId1, e3.slice()); - int logId3 = logIdFromLocation(loc3); - assertThat(logId3, equalTo(3)); - } - } - - @Test - public void testReadLog() throws Exception { - File ledgerDir = tmpDirs.createNew("logRolling", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 100); - ByteBuf e2 = makeEntry(ledgerId1, 2L, 100); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 100); - - try (EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 200000, // max file size (header + size of one entry) - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - long loc1 = elog.addEntry(ledgerId1, e1.slice()); - long loc2 = elog.addEntry(ledgerId1, e2.slice()); - elog.flush(); - - ByteBuf e1read = elog.readEntry(ledgerId1, 1L, loc1); - ByteBuf e2read = elog.readEntry(ledgerId1, 2L, loc2); - assertEntryEquals(e1read, e1); - assertEntryEquals(e2read, e2); - ReferenceCountUtil.release(e1read); - ReferenceCountUtil.release(e2read); - - long loc3 = elog.addEntry(ledgerId1, e3.slice()); - elog.flush(); - - ByteBuf e3read = elog.readEntry(ledgerId1, 3L, loc3); - assertEntryEquals(e3read, e3); - ReferenceCountUtil.release(e3read); - } - } - - @Test - public void testLogReaderCleanup() throws Exception { - File ledgerDir = tmpDirs.createNew("logRolling", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - final int entrySize = Buffer.ALIGNMENT; - final int maxFileSize = Header.EMPTY_HEADER.length + entrySize; - final int maxCachedReaders = 16; - - AtomicInteger outstandingReaders = new AtomicInteger(0); - EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - maxFileSize, - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - maxCachedReaders * maxFileSize, // total read buffer size - maxFileSize, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE) { - @Override - LogReader newDirectReader(int logId) throws IOException { - outstandingReaders.incrementAndGet(); - return new DirectReader(logId, logFilename(curDir, logId), ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, 10 * 1024 * 1024, - NullStatsLogger.INSTANCE.getOpStatsLogger("")) { - @Override - public void close() throws IOException { - super.close(); - outstandingReaders.decrementAndGet(); - } - }; - } - }; - try { - List locations = new ArrayList<>(); - // `+ 1` is not a typo: create one more log file than the max number of o cached readers - for (int i = 0; i < maxCachedReaders + 1; i++) { - ByteBuf e = makeEntry(ledgerId1, i, entrySize); - long loc = elog.addEntry(ledgerId1, e.slice()); - locations.add(loc); - } - elog.flush(); - for (Long loc : locations) { - ReferenceCountUtil.release(elog.readEntry(loc)); - } - assertThat(outstandingReaders.get(), equalTo(maxCachedReaders)); - } finally { - elog.close(); - } - assertThat(outstandingReaders.get(), equalTo(0)); - } - - @Test - public void testReadMetadataAndScan() throws Exception { - File ledgerDir = tmpDirs.createNew("directCanReadAndScanMeta", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long ledgerId1 = 1L; - long ledgerId2 = 2L; - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 1000); - ByteBuf e2 = makeEntry(ledgerId2, 2L, 2000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 3000); - - long loc1, loc2, loc3; - try (DirectEntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 2 << 16, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc1 = elog.addEntry(ledgerId1, e1); - loc2 = elog.addEntry(ledgerId2, e2); - loc3 = elog.addEntry(ledgerId1, e3); - } - - try (DirectEntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 2 << 16, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - int logId = logIdFromLocation(loc1); - assertThat(logId, equalTo(logIdFromLocation(loc2))); - assertThat(logId, equalTo(logIdFromLocation(loc3))); - - EntryLogMetadata metaRead = elog.readEntryLogIndex(logId); - assertThat(metaRead.getEntryLogId(), equalTo((long) logId)); - assertThat(metaRead.getTotalSize(), equalTo(1000L + 2000 + 3000 + (Integer.BYTES * 3))); - assertThat(metaRead.getRemainingSize(), equalTo(metaRead.getTotalSize())); - assertThat(metaRead.getLedgersMap().get(ledgerId1), equalTo(1000L + 3000L + (Integer.BYTES * 2))); - assertThat(metaRead.getLedgersMap().get(ledgerId2), equalTo(2000L + Integer.BYTES)); - - EntryLogMetadata metaScan = elog.scanEntryLogMetadata(logId, null); - assertThat(metaScan.getEntryLogId(), equalTo((long) logId)); - assertThat(metaScan.getTotalSize(), equalTo(1000L + 2000 + 3000 + (Integer.BYTES * 3))); - assertThat(metaScan.getRemainingSize(), equalTo(metaScan.getTotalSize())); - assertThat(metaScan.getLedgersMap().get(ledgerId1), equalTo(1000L + 3000L + (Integer.BYTES * 2))); - assertThat(metaScan.getLedgersMap().get(ledgerId2), equalTo(2000L + Integer.BYTES)); - } - } - - @Test - public void testMetadataFallback() throws Exception { - File ledgerDir = tmpDirs.createNew("directMetaFallback", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long ledgerId1 = 1L; - long ledgerId2 = 2L; - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 1000); - ByteBuf e2 = makeEntry(ledgerId2, 2L, 2000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 3000); - - int maxFileSize = 1000 + 2000 + 3000 + (Integer.BYTES * 3) + 4096; - long loc1, loc2, loc3; - try (DirectEntryLogger writer = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 2 << 16, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc1 = writer.addEntry(ledgerId1, e1); - loc2 = writer.addEntry(ledgerId2, e2); - loc3 = writer.addEntry(ledgerId1, e3); - writer.flush(); - - try (DirectEntryLogger reader = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 2 << 16, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - int logId = logIdFromLocation(loc1); - try { - reader.readEntryLogIndex(logId); - Assert.fail("Shouldn't be there"); - } catch (IOException ioe) { - // expected - } - - EntryLogMetadata metaRead = reader.getEntryLogMetadata(logId); // should fail read, fallback to scan - assertThat(metaRead.getEntryLogId(), equalTo((long) logId)); - assertThat(metaRead.getTotalSize(), equalTo(1000L + 2000 + 3000 + (Integer.BYTES * 3))); - assertThat(metaRead.getRemainingSize(), equalTo(metaRead.getTotalSize())); - assertThat(metaRead.getLedgersMap().get(ledgerId1), equalTo(1000L + 3000L + (Integer.BYTES * 2))); - assertThat(metaRead.getLedgersMap().get(ledgerId2), equalTo(2000L + Integer.BYTES)); - } - } - } - - @Test - public void testMetadataManyBatch() throws Exception { - File ledgerDir = tmpDirs.createNew("directMetaManyBatches", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long lastLoc = -1; - int ledgerCount = 11000; - try (DirectEntryLogger writer = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 2 << 24, // max file size - 10 * 1024 * 1024, // max sane entry size - 32 * 1024 * 1024, // total write buffer size - 32 * 1024 * 1024, // total read buffer size - 16 * 1024 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - for (int i = 0; i < ledgerCount; i++) { - long loc = writer.addEntry(i, makeEntry(i, 1L, 1000)); - if (lastLoc >= 0) { - assertThat(logIdFromLocation(loc), equalTo(logIdFromLocation(lastLoc))); - } - lastLoc = loc; - } - writer.flush(); - } - - try (DirectEntryLogger reader = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 2 << 20, // max file size - 10 * 1024 * 1024, // max sane entry size - 32 * 1024 * 1024, // total write buffer size - 32 * 1024 * 1024, // total read buffer size - 16 * 1024 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - int logId = logIdFromLocation(lastLoc); - EntryLogMetadata metaRead = reader.readEntryLogIndex(logId); - - assertThat(metaRead.getEntryLogId(), equalTo((long) logId)); - assertThat(metaRead.getTotalSize(), equalTo((1000L + Integer.BYTES) * ledgerCount)); - assertThat(metaRead.getRemainingSize(), equalTo(metaRead.getTotalSize())); - for (int i = 0; i < ledgerCount; i++) { - assertThat(metaRead.getLedgersMap().containsKey(i), equalTo(true)); - } - } - } - - @Test - public void testGetFlushedLogs() throws Exception { - File ledgerDir = tmpDirs.createNew("testFlushedLogs", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ExecutorService executor = Executors.newFixedThreadPool(5); - CompletableFuture blockClose = new CompletableFuture<>(); - NativeIOImpl nativeIO = new NativeIOImpl() { - @Override - public int close(int fd) { - try { - blockClose.join(); - return super.close(fd); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - }; - DirectEntryLogger entryLogger = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - nativeIO, - ByteBufAllocator.DEFAULT, - executor, - executor, - 23000, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 32 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE); - try { // not using try-with-resources because close needs to be unblocked in failure - // Add entries. - // Ledger 1 is on first entry log - // Ledger 2 spans first, second and third entry log - // Ledger 3 is on the third entry log (which is still active when extract meta) - long loc1 = entryLogger.addEntry(1L, makeEntry(1L, 1L, 5000)); - long loc2 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 5000)); - assertThat(logIdFromLocation(loc2), equalTo(logIdFromLocation(loc1))); - long loc3 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 15000)); - assertThat(logIdFromLocation(loc3), greaterThan(logIdFromLocation(loc2))); - long loc4 = entryLogger.addEntry(2L, makeEntry(2L, 1L, 15000)); - assertThat(logIdFromLocation(loc4), greaterThan(logIdFromLocation(loc3))); - long loc5 = entryLogger.addEntry(3L, makeEntry(3L, 1L, 1000)); - assertThat(logIdFromLocation(loc5), equalTo(logIdFromLocation(loc4))); - - long logId1 = logIdFromLocation(loc2); - long logId2 = logIdFromLocation(loc3); - long logId3 = logIdFromLocation(loc5); - - // all three should exist - assertThat(entryLogger.logExists(logId1), equalTo(true)); - assertThat(entryLogger.logExists(logId2), equalTo(true)); - assertThat(entryLogger.logExists(logId3), equalTo(true)); - - assertThat(entryLogger.getFlushedLogIds(), empty()); - - blockClose.complete(null); - entryLogger.flush(); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2)); - - long loc6 = entryLogger.addEntry(3L, makeEntry(3L, 1L, 25000)); - assertThat(logIdFromLocation(loc6), greaterThan(logIdFromLocation(loc5))); - entryLogger.flush(); - - assertThat(entryLogger.getFlushedLogIds(), containsInAnyOrder(logId1, logId2, logId3)); - } finally { - blockClose.complete(null); - entryLogger.close(); - executor.shutdownNow(); - } - } - - @Test - public void testBufferSizeNotPageAligned() throws Exception { - File ledgerDir = tmpDirs.createNew("logRolling", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 4000); - ByteBuf e2 = makeEntry(ledgerId1, 2L, 4000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 4000); - - try (EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 9000, // max file size (header + size of one entry) - 10 * 1024 * 1024, // max sane entry size - 128 * 1024 + 500, // total write buffer size - 128 * 1024 + 300, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - long loc1 = elog.addEntry(ledgerId1, e1.slice()); - int logId1 = logIdFromLocation(loc1); - assertThat(logId1, equalTo(1)); - - long loc2 = elog.addEntry(ledgerId1, e2.slice()); - int logId2 = logIdFromLocation(loc2); - assertThat(logId2, equalTo(2)); - - long loc3 = elog.addEntry(ledgerId1, e3.slice()); - int logId3 = logIdFromLocation(loc3); - assertThat(logId3, equalTo(3)); - } - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLoggerCompat.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLoggerCompat.java deleted file mode 100644 index 8e1ff6baf61..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLoggerCompat.java +++ /dev/null @@ -1,651 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.assertEntryEquals; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.logIdFromLocation; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.makeEntry; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newLegacyEntryLogger; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.not; - -import com.google.common.util.concurrent.MoreExecutors; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.nio.charset.StandardCharsets; -import org.apache.bookkeeper.bookie.DefaultEntryLogger; -import org.apache.bookkeeper.bookie.EntryLogMetadata; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.storage.EntryLogger; -import org.apache.bookkeeper.bookie.storage.MockEntryLogIds; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.bookkeeper.util.DiskChecker; -import org.junit.After; -import org.junit.Test; - -/** - * TestDirectEntryLoggerCompat. - */ -public class TestDirectEntryLoggerCompat { - private final Slogger slog = Slogger.CONSOLE; - - private static final long ledgerId1 = 1234; - private static final long ledgerId2 = 4567; - private static final long ledgerId3 = 7890; - - private final TmpDirs tmpDirs = new TmpDirs(); - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - } - - @Test - public void testLegacyCanReadDirect() throws Exception { - File ledgerDir = tmpDirs.createNew("legacyCanRead", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 1000); - ByteBuf e2 = makeEntry(ledgerId1, 2L, 1000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 1000); - - long loc1, loc2, loc3; - try (EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 10 * 1024 * 1024, // 10MiB, max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc1 = elog.addEntry(ledgerId1, e1.slice()); - loc2 = elog.addEntry(ledgerId1, e2.slice()); - loc3 = elog.addEntry(ledgerId1, e3.slice()); - } - - try (EntryLogger legacy = newLegacyEntryLogger(2000000, ledgerDir)) { - assertEntryEquals(legacy.readEntry(ledgerId1, 1L, loc1), e1); - assertEntryEquals(legacy.readEntry(ledgerId1, 2L, loc2), e2); - assertEntryEquals(legacy.readEntry(ledgerId1, 3L, loc3), e3); - } - } - - @Test - public void testDirectCanReadLegacy() throws Exception { - File ledgerDir = tmpDirs.createNew("legacyCanRead", "ledgers"); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 1000); - ByteBuf e2 = makeEntry(ledgerId1, 2L, 1000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 1000); - - long loc1, loc2, loc3; - try (EntryLogger legacy = newLegacyEntryLogger(2000000, ledgerDir)) { - loc1 = legacy.addEntry(ledgerId1, e1.slice()); - loc2 = legacy.addEntry(ledgerId1, e2.slice()); - loc3 = legacy.addEntry(ledgerId1, e3.slice()); - legacy.flush(); - } - - try (EntryLogger elog = new DirectEntryLogger( - new File(ledgerDir, "current"), new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 10 * 1024 * 1024, // 10MiB, max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - assertEntryEquals(elog.readEntry(ledgerId1, 1L, loc1), e1); - assertEntryEquals(elog.readEntry(ledgerId1, 2L, loc2), e2); - assertEntryEquals(elog.readEntry(ledgerId1, 3L, loc3), e3); - } - } - - @Test - public void testLegacyCanReadDirectAfterMultipleRolls() throws Exception { - File ledgerDir = tmpDirs.createNew("legacyCanRead", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 4000); - ByteBuf e2 = makeEntry(ledgerId1, 2L, 4000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 4000); - - long loc1, loc2, loc3; - try (EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 6000, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc1 = elog.addEntry(ledgerId1, e1.slice()); - loc2 = elog.addEntry(ledgerId1, e2.slice()); - loc3 = elog.addEntry(ledgerId1, e3.slice()); - } - - try (EntryLogger legacy = newLegacyEntryLogger(2000000, ledgerDir)) { - assertEntryEquals(legacy.readEntry(ledgerId1, 1L, loc1), e1); - assertEntryEquals(legacy.readEntry(ledgerId1, 2L, loc2), e2); - assertEntryEquals(legacy.readEntry(ledgerId1, 3L, loc3), e3); - } - } - - @Test - public void testLegacyCanReadMetadataOfDirectWithIndexWritten() throws Exception { - File ledgerDir = tmpDirs.createNew("legacyCanReadMeta", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 1000); - ByteBuf e2 = makeEntry(ledgerId2, 2L, 2000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 3000); - ByteBuf e4 = makeEntry(ledgerId1, 4L, 4000); - - int maxFileSize = 1000 + 2000 + 3000 + (Integer.BYTES * 3) + 4096; - long loc1, loc2, loc3, loc4; - try (EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - maxFileSize, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc1 = elog.addEntry(ledgerId1, e1); - loc2 = elog.addEntry(ledgerId2, e2); - loc3 = elog.addEntry(ledgerId1, e3); - loc4 = elog.addEntry(ledgerId1, e4); - } - - try (EntryLogger legacy = newLegacyEntryLogger( - maxFileSize, // size of first 3 entries + header - ledgerDir)) { - int logId = logIdFromLocation(loc1); - assertThat(logId, equalTo(logIdFromLocation(loc2))); - assertThat(logId, equalTo(logIdFromLocation(loc3))); - assertThat(logId, not(equalTo(logIdFromLocation(loc4)))); - - EntryLogMetadata meta = legacy.getEntryLogMetadata(logId); - - assertThat(meta.getEntryLogId(), equalTo((long) logId)); - assertThat(meta.getTotalSize(), equalTo(1000L + 2000 + 3000 + (Integer.BYTES * 3))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - assertThat(meta.getLedgersMap().get(ledgerId1), equalTo(1000L + 3000L + (Integer.BYTES * 2))); - assertThat(meta.getLedgersMap().get(ledgerId2), equalTo(2000L + Integer.BYTES)); - } - } - - @Test - public void testLegacyCanReadMetadataOfDirectWithNoIndexWritten() throws Exception { - File ledgerDir = tmpDirs.createNew("legacyCanReadMeta", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 1000); - ByteBuf e2 = makeEntry(ledgerId2, 2L, 2000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 3000); - ByteBuf e4 = makeEntry(ledgerId1, 4L, 4000); - - int maxFileSize = 1000 + 2000 + 3000 + (Integer.BYTES * 3) + 4096; - long loc1, loc2, loc3; - try (EntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - maxFileSize * 10, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc1 = elog.addEntry(ledgerId1, e1); - loc2 = elog.addEntry(ledgerId2, e2); - loc3 = elog.addEntry(ledgerId1, e3); - } - - try (EntryLogger legacy = newLegacyEntryLogger( - maxFileSize, // size of first 3 entries + header - ledgerDir)) { - int logId = logIdFromLocation(loc1); - assertThat(logId, equalTo(logIdFromLocation(loc2))); - assertThat(logId, equalTo(logIdFromLocation(loc3))); - EntryLogMetadata meta = legacy.getEntryLogMetadata(logId); - - assertThat(meta.getEntryLogId(), equalTo((long) logId)); - assertThat(meta.getTotalSize(), equalTo(1000L + 2000 + 3000 + (Integer.BYTES * 3))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - assertThat(meta.getLedgersMap().get(ledgerId1), equalTo(1000L + 3000L + (Integer.BYTES * 2))); - assertThat(meta.getLedgersMap().get(ledgerId2), equalTo(2000L + Integer.BYTES)); - } - } - - @Test - public void testDirectCanReadMetadataAndScanFromLegacy() throws Exception { - File ledgerDir = tmpDirs.createNew("directCanReadLegacyMeta", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - ByteBuf e1 = makeEntry(ledgerId1, 1L, 1000); - ByteBuf e2 = makeEntry(ledgerId2, 2L, 2000); - ByteBuf e3 = makeEntry(ledgerId1, 3L, 3000); - ByteBuf e4 = makeEntry(ledgerId1, 4L, 4000); - - int maxFileSize = 1000 + 2000 + 3000 + (Integer.BYTES * 3) + 4096; - long loc1, loc2, loc3, loc4; - try (EntryLogger legacy = newLegacyEntryLogger( - maxFileSize, // size of first 3 entries + header - ledgerDir)) { - loc1 = legacy.addEntry(ledgerId1, e1); - loc2 = legacy.addEntry(ledgerId2, e2); - loc3 = legacy.addEntry(ledgerId1, e3); - loc4 = legacy.addEntry(ledgerId1, e4); // should force a roll - } - - try (DirectEntryLogger elog = new DirectEntryLogger( - curDir, new MockEntryLogIds(), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - maxFileSize * 10, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - int logId = logIdFromLocation(loc1); - assertThat(logId, equalTo(logIdFromLocation(loc2))); - assertThat(logId, equalTo(logIdFromLocation(loc3))); - assertThat(logId, not(equalTo(logIdFromLocation(loc4)))); - - EntryLogMetadata metaRead = elog.readEntryLogIndex(logId); - assertThat(metaRead.getEntryLogId(), equalTo((long) logId)); - assertThat(metaRead.getTotalSize(), equalTo(1000L + 2000 + 3000 + (Integer.BYTES * 3))); - assertThat(metaRead.getRemainingSize(), equalTo(metaRead.getTotalSize())); - assertThat(metaRead.getLedgersMap().get(ledgerId1), equalTo(1000L + 3000L + (Integer.BYTES * 2))); - assertThat(metaRead.getLedgersMap().get(ledgerId2), equalTo(2000L + Integer.BYTES)); - - EntryLogMetadata metaScan = elog.scanEntryLogMetadata(logId, null); - assertThat(metaScan.getEntryLogId(), equalTo((long) logId)); - assertThat(metaScan.getTotalSize(), equalTo(1000L + 2000 + 3000 + (Integer.BYTES * 3))); - assertThat(metaScan.getRemainingSize(), equalTo(metaScan.getTotalSize())); - assertThat(metaScan.getLedgersMap().get(ledgerId1), equalTo(1000L + 3000L + (Integer.BYTES * 2))); - assertThat(metaScan.getLedgersMap().get(ledgerId2), equalTo(2000L + Integer.BYTES)); - } - } - - // step1: default is DirectEntryLogger, write entries, read entries - // step2: change DirectEntryLogger to DefaultEntryLogger, write entries, and read all entries both written - // by DirectEntryLogger and DefaultEntryLogger - // step3: change DefaultEntryLogger to DirectEntryLogger, write entries, and read all entries written by - // DirectEntryLogger, DefaultEntryLogger and DirectEntryLogger. - // DirectEntryLogger -> DefaultEntryLogge -> DirectEntryLogger. - @Test - public void testCompatFromDirectToDefaultToDirectLogger() throws Exception { - File ledgerDir = tmpDirs.createNew("entryCompatTest", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - MockEntryLogIds entryLogIds = new MockEntryLogIds(); - - ByteBuf e1 = buildEntry(ledgerId1, 1, 1024, "entry-1".getBytes(StandardCharsets.UTF_8)); - ByteBuf e2 = buildEntry(ledgerId1, 2, 1024, "entry-2".getBytes(StandardCharsets.UTF_8)); - ByteBuf e3 = buildEntry(ledgerId1, 3, 1024, "entry-3".getBytes(StandardCharsets.UTF_8)); - ByteBuf e4 = buildEntry(ledgerId1, 4, 1024, "entry-4".getBytes(StandardCharsets.UTF_8)); - ByteBuf e5 = buildEntry(ledgerId1, 5, 1024, "entry-5".getBytes(StandardCharsets.UTF_8)); - ByteBuf e6 = buildEntry(ledgerId1, 6, 1024, "entry-6".getBytes(StandardCharsets.UTF_8)); - ByteBuf e7 = buildEntry(ledgerId1, 7, 1024, "entry-7".getBytes(StandardCharsets.UTF_8)); - - long loc1, loc2, loc3, loc4, loc5, loc6, loc7; - - // write entry into DirectEntryLogger - try (EntryLogger elog = new DirectEntryLogger( - curDir, entryLogIds, - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 9000, // max file size (header + size of one entry) - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc1 = elog.addEntry(ledgerId1, e1.slice()); - loc2 = elog.addEntry(ledgerId1, e2.slice()); - loc3 = elog.addEntry(ledgerId1, e3.slice()); - elog.flush(); - - ByteBuf entry1 = elog.readEntry(ledgerId1, 1, loc1); - ByteBuf entry2 = elog.readEntry(ledgerId1, 2, loc2); - ByteBuf entry3 = elog.readEntry(ledgerId1, 3, loc3); - - assertEntryEquals(entry1, e1); - assertEntryEquals(entry2, e2); - assertEntryEquals(entry3, e3); - - entry1.release(); - entry2.release(); - entry3.release(); - } - - // read entry from DefaultEntryLogger - ServerConfiguration conf = new ServerConfiguration(); - LedgerDirsManager dirsMgr = new LedgerDirsManager( - conf, - new File[] { ledgerDir }, - new DiskChecker( - conf.getDiskUsageThreshold(), - conf.getDiskUsageWarnThreshold())); - EntryLogger entryLogger = new DefaultEntryLogger(conf, dirsMgr); - loc4 = entryLogger.addEntry(ledgerId1, e4.slice()); - loc5 = entryLogger.addEntry(ledgerId1, e5.slice()); - entryLogger.flush(); - - ByteBuf entry1 = entryLogger.readEntry(ledgerId1, 1, loc1); - ByteBuf entry2 = entryLogger.readEntry(ledgerId1, 2, loc2); - ByteBuf entry3 = entryLogger.readEntry(ledgerId1, 3, loc3); - ByteBuf entry4 = entryLogger.readEntry(ledgerId1, 4, loc4); - ByteBuf entry5 = entryLogger.readEntry(ledgerId1, 5, loc5); - - assertEntryEquals(entry1, e1); - assertEntryEquals(entry2, e2); - assertEntryEquals(entry3, e3); - assertEntryEquals(entry4, e4); - assertEntryEquals(entry5, e5); - - entry1.release(); - entry2.release(); - entry3.release(); - entry4.release(); - entry5.release(); - - // use DirectEntryLogger to read entries written by both DirectEntryLogger and DefaultEntryLogger - entryLogIds.nextId(); - try (EntryLogger elog = new DirectEntryLogger( - curDir, entryLogIds, - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 9000, // max file size (header + size of one entry) - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc6 = elog.addEntry(ledgerId1, e6.slice()); - loc7 = elog.addEntry(ledgerId1, e7.slice()); - elog.flush(); - - entry1 = elog.readEntry(ledgerId1, 1, loc1); - entry2 = elog.readEntry(ledgerId1, 2, loc2); - entry3 = elog.readEntry(ledgerId1, 3, loc3); - entry4 = elog.readEntry(ledgerId1, 4, loc4); - entry5 = elog.readEntry(ledgerId1, 5, loc5); - ByteBuf entry6 = elog.readEntry(ledgerId1, 6, loc6); - ByteBuf entry7 = elog.readEntry(ledgerId1, 7, loc7); - - assertEntryEquals(entry1, e1); - assertEntryEquals(entry2, e2); - assertEntryEquals(entry3, e3); - assertEntryEquals(entry4, e4); - assertEntryEquals(entry5, e5); - assertEntryEquals(entry6, e6); - assertEntryEquals(entry7, e7); - - entry1.release(); - entry2.release(); - entry3.release(); - entry4.release(); - entry5.release(); - entry6.release(); - entry7.release(); - } - - ledgerDir.deleteOnExit(); - - } - - // step1: default is DefaultEntryLogger, write entries and read entries. - // step2: change DefaultEntryLogger to DirectEntryLogger, write entries, and read all entries both writer - // by DefaultEntryLogger and DirectEntryLogger - // step3: change DirectEntryLogger to DefaultEntryLogger, write entries, and read all entries both written - // by DirectEntryLogger and DefaultEntryLogger - // step4: change DefaultEntryLogger to DirectEntryLogger, write entries, and read all entries written by - // DirectEntryLogger, DefaultEntryLogger and DirectEntryLogger. - // DefaultEntryLogger -> DirectEntryLogger -> DefaultEntryLogger -> DirectEntryLogger. - @Test - public void testCompatFromDefaultToDirectToDefaultToDirectLogger() throws Exception { - File ledgerDir = tmpDirs.createNew("entryCompatTest", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - MockEntryLogIds entryLogIds = new MockEntryLogIds(); - - ByteBuf e1 = buildEntry(ledgerId1, 1, 1024, "entry-1".getBytes(StandardCharsets.UTF_8)); - ByteBuf e2 = buildEntry(ledgerId1, 2, 1024, "entry-2".getBytes(StandardCharsets.UTF_8)); - ByteBuf e3 = buildEntry(ledgerId1, 3, 1024, "entry-3".getBytes(StandardCharsets.UTF_8)); - ByteBuf e4 = buildEntry(ledgerId1, 4, 1024, "entry-4".getBytes(StandardCharsets.UTF_8)); - ByteBuf e5 = buildEntry(ledgerId1, 5, 1024, "entry-5".getBytes(StandardCharsets.UTF_8)); - ByteBuf e6 = buildEntry(ledgerId1, 6, 1024, "entry-6".getBytes(StandardCharsets.UTF_8)); - ByteBuf e7 = buildEntry(ledgerId1, 7, 1024, "entry-7".getBytes(StandardCharsets.UTF_8)); - ByteBuf e8 = buildEntry(ledgerId1, 8, 1024, "entry-8".getBytes(StandardCharsets.UTF_8)); - ByteBuf e9 = buildEntry(ledgerId1, 9, 1024, "entry-9".getBytes(StandardCharsets.UTF_8)); - - long loc1, loc2, loc3, loc4, loc5, loc6, loc7, loc8, loc9; - - // write e1 and e2 using DefaultEntryLogger - ServerConfiguration conf = new ServerConfiguration(); - LedgerDirsManager dirsMgr = new LedgerDirsManager( - conf, - new File[] { ledgerDir }, - new DiskChecker( - conf.getDiskUsageThreshold(), - conf.getDiskUsageWarnThreshold())); - EntryLogger entryLogger = new DefaultEntryLogger(conf, dirsMgr); - loc1 = entryLogger.addEntry(ledgerId1, e1.slice()); - loc2 = entryLogger.addEntry(ledgerId1, e2.slice()); - entryLogger.flush(); - - ByteBuf entry1 = entryLogger.readEntry(ledgerId1, 1, loc1); - ByteBuf entry2 = entryLogger.readEntry(ledgerId1, 2, loc2); - - assertEntryEquals(entry1, e1); - assertEntryEquals(entry2, e2); - - entry1.release(); - entry2.release(); - - // write e3, e4 and e5 using DirectEntryLogger and read all entries. - entryLogIds.nextId(); - try (EntryLogger elog = new DirectEntryLogger( - curDir, entryLogIds, - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 9000, // max file size (header + size of one entry) - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc3 = elog.addEntry(ledgerId1, e3.slice()); - loc4 = elog.addEntry(ledgerId1, e4.slice()); - loc5 = elog.addEntry(ledgerId1, e5.slice()); - elog.flush(); - - entry1 = elog.readEntry(ledgerId1, 1, loc1); - entry2 = elog.readEntry(ledgerId1, 2, loc2); - ByteBuf entry3 = elog.readEntry(ledgerId1, 3, loc3); - ByteBuf entry4 = elog.readEntry(ledgerId1, 4, loc4); - ByteBuf entry5 = elog.readEntry(ledgerId1, 5, loc5); - - assertEntryEquals(entry1, e1); - assertEntryEquals(entry2, e2); - assertEntryEquals(entry3, e3); - assertEntryEquals(entry4, e4); - assertEntryEquals(entry5, e5); - - entry1.release(); - entry2.release(); - entry3.release(); - entry4.release(); - entry5.release(); - } - - // write e6 and e7 using DefaultEntryLogger and read all entries - entryLogger = new DefaultEntryLogger(conf, dirsMgr); - loc6 = entryLogger.addEntry(ledgerId1, e6.slice()); - loc7 = entryLogger.addEntry(ledgerId1, e7.slice()); - entryLogger.flush(); - - entry1 = entryLogger.readEntry(ledgerId1, 1, loc1); - entry2 = entryLogger.readEntry(ledgerId1, 2, loc2); - ByteBuf entry3 = entryLogger.readEntry(ledgerId1, 3, loc3); - ByteBuf entry4 = entryLogger.readEntry(ledgerId1, 4, loc4); - ByteBuf entry5 = entryLogger.readEntry(ledgerId1, 5, loc5); - ByteBuf entry6 = entryLogger.readEntry(ledgerId1, 6, loc6); - ByteBuf entry7 = entryLogger.readEntry(ledgerId1, 7, loc7); - - assertEntryEquals(entry1, e1); - assertEntryEquals(entry2, e2); - assertEntryEquals(entry3, e3); - assertEntryEquals(entry4, e4); - assertEntryEquals(entry5, e5); - assertEntryEquals(entry6, e6); - assertEntryEquals(entry7, e7); - - entry1.release(); - entry2.release(); - entry3.release(); - entry4.release(); - entry5.release(); - entry6.release(); - entry7.release(); - - // use DirectEntryLogger to read entries written by both DirectEntryLogger and DefaultEntryLogger - entryLogIds.nextId(); - try (EntryLogger elog = new DirectEntryLogger( - curDir, entryLogIds, - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 9000, // max file size (header + size of one entry) - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 64 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE)) { - loc8 = elog.addEntry(ledgerId1, e8.slice()); - loc9 = elog.addEntry(ledgerId1, e9.slice()); - elog.flush(); - - entry1 = elog.readEntry(ledgerId1, 1, loc1); - entry2 = elog.readEntry(ledgerId1, 2, loc2); - entry3 = elog.readEntry(ledgerId1, 3, loc3); - entry4 = elog.readEntry(ledgerId1, 4, loc4); - entry5 = elog.readEntry(ledgerId1, 5, loc5); - entry6 = elog.readEntry(ledgerId1, 6, loc6); - entry7 = elog.readEntry(ledgerId1, 7, loc7); - ByteBuf entry8 = elog.readEntry(ledgerId1, 8, loc8); - ByteBuf entry9 = elog.readEntry(ledgerId1, 9, loc9); - - assertEntryEquals(entry1, e1); - assertEntryEquals(entry2, e2); - assertEntryEquals(entry3, e3); - assertEntryEquals(entry4, e4); - assertEntryEquals(entry5, e5); - assertEntryEquals(entry6, e6); - assertEntryEquals(entry7, e7); - assertEntryEquals(entry8, e8); - assertEntryEquals(entry9, e9); - - entry1.release(); - entry2.release(); - entry3.release(); - entry4.release(); - entry5.release(); - entry6.release(); - entry7.release(); - entry8.release(); - entry9.release(); - } - - ledgerDir.deleteOnExit(); - } - - private ByteBuf buildEntry(long ledgerId, long entryId, int size, byte[] bytes) { - ByteBuf entry = Unpooled.buffer(size); - entry.writeLong(ledgerId); // ledger id - entry.writeLong(entryId); // entry id - entry.writeBytes(bytes); - return entry; - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectReader.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectReader.java deleted file mode 100644 index 75ad4437e9e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectReader.java +++ /dev/null @@ -1,516 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.apache.bookkeeper.bookie.storage.directentrylogger.DirectEntryLogger.logFilename; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import com.google.common.util.concurrent.MoreExecutors; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.apache.bookkeeper.common.util.nativeio.NativeIOException; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.commons.lang3.SystemUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - - -/** - * TestDirectReader. - */ -public class TestDirectReader { - - private final TmpDirs tmpDirs = new TmpDirs(); - private final ExecutorService writeExecutor = Executors.newSingleThreadExecutor(); - private final OpStatsLogger opLogger = NullStatsLogger.INSTANCE.getOpStatsLogger("null"); - - @Before - public void before() { - Assume.assumeFalse(SystemUtils.IS_OS_WINDOWS); - } - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - writeExecutor.shutdownNow(); - } - - @Test - public void testReadInt() throws Exception { - File ledgerDir = tmpDirs.createNew("readInt", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xdeadbeef, 0, 1 << 20); - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - assertThat(reader.readIntAt(0), equalTo(0xdeadbeef)); - assertThat(reader.readIntAt(2), equalTo(0xbeefdead)); - assertThat(reader.readIntAt(1024), equalTo(0xdeadbeef)); - assertThat(reader.readIntAt(1025), equalTo(0xadbeefde)); - } - } - - @Test - public void testReadIntAcrossBoundary() throws Exception { - File ledgerDir = tmpDirs.createNew("readInt", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xdeadbeef, 0, 1 << 20); - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - assertThat(reader.readIntAt(Buffer.ALIGNMENT - 2), equalTo(0xbeefdead)); - } - } - - @Test - public void testReadLong() throws Exception { - File ledgerDir = tmpDirs.createNew("readLong", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xbeefcafe, 0, 1 << 20); - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - assertThat(reader.readLongAt(0), equalTo(0xbeefcafebeefcafeL)); - assertThat(reader.readLongAt(2), equalTo(0xcafebeefcafebeefL)); - assertThat(reader.readLongAt(1024), equalTo(0xbeefcafebeefcafeL)); - assertThat(reader.readLongAt(1025), equalTo(0xefcafebeefcafebeL)); - } - } - - @Test - public void testReadLongAcrossBoundary() throws Exception { - File ledgerDir = tmpDirs.createNew("readLong", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xbeefcafe, 0, 1 << 20); - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - assertThat(reader.readLongAt(0), equalTo(0xbeefcafebeefcafeL)); - assertThat(reader.readLongAt(2), equalTo(0xcafebeefcafebeefL)); - assertThat(reader.readLongAt(1024), equalTo(0xbeefcafebeefcafeL)); - assertThat(reader.readLongAt(1025), equalTo(0xefcafebeefcafebeL)); - } - } - - @Test - public void testReadBuffer() throws Exception { - File ledgerDir = tmpDirs.createNew("readBuffer", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xbeefcafe, 1, 1 << 20); - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT * 4, - 1 << 20, opLogger)) { - ByteBuf bb = reader.readBufferAt(0, Buffer.ALIGNMENT * 2); - try { - for (int j = 0; j < Buffer.ALIGNMENT / Integer.BYTES; j++) { - assertThat(bb.readInt(), equalTo(0xbeefcafe)); - } - for (int i = 0; i < Buffer.ALIGNMENT / Integer.BYTES; i++) { - assertThat(bb.readInt(), equalTo(0xbeefcaff)); - } - assertThat(bb.readableBytes(), equalTo(0)); - } finally { - bb.release(); - } - - bb = reader.readBufferAt(Buffer.ALIGNMENT * 8, Buffer.ALIGNMENT); - try { - for (int j = 0; j < Buffer.ALIGNMENT / Integer.BYTES; j++) { - assertThat(bb.readInt(), equalTo(0xbeefcb06)); - } - assertThat(bb.readableBytes(), equalTo(0)); - } finally { - bb.release(); - } - - bb = reader.readBufferAt(Buffer.ALIGNMENT * 10 + 123, 345); - try { - assertThat(bb.readByte(), equalTo((byte) 0x08)); - for (int j = 0; j < 344 / Integer.BYTES; j++) { - assertThat(bb.readInt(), equalTo(0xbeefcb08)); - } - assertThat(bb.readableBytes(), equalTo(0)); - } finally { - bb.release(); - } - - } - } - - @Test - public void testReadBufferAcrossBoundary() throws Exception { - File ledgerDir = tmpDirs.createNew("readBuffer", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xbeefcafe, 1, 1 << 20); - BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT * 4, 8); - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT * 4, - 1 << 20, opLogger)) { - ByteBuf bb = reader.readBufferAt((long) (Buffer.ALIGNMENT * 3.5), Buffer.ALIGNMENT); - try { - for (int j = 0; j < (Buffer.ALIGNMENT / Integer.BYTES) / 2; j++) { - assertThat(bb.readInt(), equalTo(0xbeefcb01)); - } - for (int i = 0; i < (Buffer.ALIGNMENT / Integer.BYTES) / 2; i++) { - assertThat(bb.readInt(), equalTo(0xbeefcb02)); - } - assertThat(bb.readableBytes(), equalTo(0)); - } finally { - bb.release(); - } - } - } - - @Test - public void testReadBufferBiggerThanReaderBuffer() throws Exception { - File ledgerDir = tmpDirs.createNew("readBuffer", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xbeefcafe, 1, 1 << 20); - - // buffer size is ALIGNMENT, read will be ALIGNMENT*2 - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - ByteBuf bb = reader.readBufferAt(0, Buffer.ALIGNMENT * 2); - try { - for (int j = 0; j < Buffer.ALIGNMENT / Integer.BYTES; j++) { - assertThat(bb.readInt(), equalTo(0xbeefcafe)); - } - for (int i = 0; i < Buffer.ALIGNMENT / Integer.BYTES; i++) { - assertThat(bb.readInt(), equalTo(0xbeefcaff)); - } - assertThat(bb.readableBytes(), equalTo(0)); - } finally { - bb.release(); - } - } - } - - @Test(expected = EOFException.class) - public void testReadPastEndOfFile() throws Exception { - File ledgerDir = tmpDirs.createNew("readBuffer", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xbeeeeeef, 1, 1 << 13); - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - reader.readBufferAt(1 << 13, Buffer.ALIGNMENT); - } - } - - @Test(expected = EOFException.class) - public void testReadPastEndOfFilePartial() throws Exception { - File ledgerDir = tmpDirs.createNew("readBuffer", "logs"); - - writeFileWithPattern(ledgerDir, 1234, 0xbeeeeeef, 1, 1 << 13); - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - reader.readBufferAt((1 << 13) - Buffer.ALIGNMENT / 2, Buffer.ALIGNMENT); - } - } - - @Test - public void testReadEntries() throws Exception { - File ledgerDir = tmpDirs.createNew("readEntries", "logs"); - - int entrySize = Buffer.ALIGNMENT / 4 + 100; - Map offset2Pattern = new HashMap<>(); - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(1234, logFilename(ledgerDir, 1234), - 1 << 20, MoreExecutors.newDirectExecutorService(), - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - for (int i = 0; i < 1000; i++) { - ByteBuf bb = Unpooled.buffer(entrySize); - int pattern = 0xbeef + i; - TestBuffer.fillByteBuf(bb, pattern); - int offset = writer.writeDelimited(bb); - offset2Pattern.put(offset, pattern); - } - } - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - List> offset2PatternList = - new ArrayList>(offset2Pattern.entrySet()); - Collections.shuffle(offset2PatternList); - - for (Map.Entry e : offset2PatternList) { - ByteBuf entry = reader.readEntryAt(e.getKey()); - try { - assertThat(entry.readableBytes(), equalTo(entrySize)); - while (entry.isReadable()) { - assertThat(entry.readInt(), equalTo(e.getValue())); - } - } finally { - entry.release(); - } - } - } - } - - @Test - public void testReadFromFileBeingWrittenNoPreallocation() throws Exception { - File ledgerDir = tmpDirs.createNew("readWhileWriting", "logs"); - - int entrySize = Buffer.ALIGNMENT / 2 + 8; - NativeIOImpl nativeIO = new NativeIOImpl() { - @Override - public int fallocate(int fd, int mode, long offset, long len) - throws NativeIOException { - return 0; - } - }; - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(1234, logFilename(ledgerDir, 1234), - 1 << 20, MoreExecutors.newDirectExecutorService(), - buffers, new NativeIOImpl(), Slogger.CONSOLE); - LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - ByteBuf b2 = Unpooled.buffer(entrySize); - TestBuffer.fillByteBuf(b2, 0xfede); - int offset = writer.writeDelimited(b2); - - try { - reader.readEntryAt(offset); - Assert.fail("Should have failed"); - } catch (IOException ioe) { - // expected - } - writer.flush(); - - ByteBuf bbread = reader.readEntryAt(offset); - try { - assertThat(bbread.readableBytes(), equalTo(entrySize)); - while (bbread.isReadable()) { - assertThat(bbread.readInt(), equalTo(0xfede)); - } - } finally { - bbread.release(); - } - } - } - - @Test - public void testReadFromFileBeingWrittenReadInPreallocated() throws Exception { - File ledgerDir = tmpDirs.createNew("readWhileWriting", "logs"); - - int entrySize = Buffer.ALIGNMENT / 2 + 8; - - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(1234, logFilename(ledgerDir, 1234), - 1 << 20, MoreExecutors.newDirectExecutorService(), - buffers, new NativeIOImpl(), Slogger.CONSOLE); - LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - ByteBuf bb = Unpooled.buffer(entrySize); - TestBuffer.fillByteBuf(bb, 0xfeed); - int offset = writer.writeDelimited(bb); - - try { - reader.readEntryAt(offset); - Assert.fail("Should have failed"); - } catch (IOException ioe) { - // expected - } - writer.flush(); - ByteBuf bbread = reader.readEntryAt(offset); - try { - assertThat(bbread.readableBytes(), equalTo(entrySize)); - while (bbread.isReadable()) { - assertThat(bbread.readInt(), equalTo(0xfeed)); - } - } finally { - bbread.release(); - } - } - } - - @Test - public void testPartialRead() throws Exception { - File ledgerDir = tmpDirs.createNew("partialRead", "logs"); - - int entrySize = Buffer.ALIGNMENT * 4; - - NativeIOImpl nativeIO = new NativeIOImpl() { - @Override - public long pread(int fd, long buf, long size, long offset) throws NativeIOException { - long read = super.pread(fd, buf, size, offset); - return Math.min(read, Buffer.ALIGNMENT); // force only less than a buffer read - } - - @Override - public int fallocate(int fd, int mode, long offset, long len) - throws NativeIOException { - return 0; // don't preallocate - } - }; - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), - ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT * 10, 8); - LogWriter writer = new DirectWriter(1234, logFilename(ledgerDir, 1234), 1 << 20, - MoreExecutors.newDirectExecutorService(), - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - ByteBuf b1 = Unpooled.buffer(entrySize); - TestBuffer.fillByteBuf(b1, 0xfeedfeed); - int offset1 = writer.writeDelimited(b1); - - ByteBuf b2 = Unpooled.buffer(entrySize); - TestBuffer.fillByteBuf(b2, 0xfedefede); - int offset2 = writer.writeDelimited(b2); - writer.flush(); - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - nativeIO, Buffer.ALIGNMENT * 3, - 1 << 20, opLogger)) { - ByteBuf bbread = reader.readEntryAt(offset1); - try { - assertThat(bbread.readableBytes(), equalTo(entrySize)); - while (bbread.readableBytes() >= Integer.BYTES) { - assertThat(bbread.readInt(), equalTo(0xfeedfeed)); - } - assertThat(bbread.readableBytes(), equalTo(0)); - } finally { - bbread.release(); - } - - bbread = reader.readEntryAt(offset2); - try { - assertThat(bbread.readableBytes(), equalTo(entrySize)); - while (bbread.readableBytes() >= Integer.BYTES) { - assertThat(bbread.readInt(), equalTo(0xfedefede)); - } - assertThat(bbread.readableBytes(), equalTo(0)); - } finally { - bbread.release(); - } - } - } - } - - @Test - public void testLargeEntry() throws Exception { - File ledgerDir = tmpDirs.createNew("largeEntries", "logs"); - - int entrySize = Buffer.ALIGNMENT * 4; - - int offset1, offset2; - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT * 8, 8); - LogWriter writer = new DirectWriter(1234, logFilename(ledgerDir, 1234), 1 << 20, - MoreExecutors.newDirectExecutorService(), buffers, new NativeIOImpl(), - Slogger.CONSOLE)) { - ByteBuf b1 = Unpooled.buffer(entrySize); - TestBuffer.fillByteBuf(b1, 0xfeedfeed); - offset1 = writer.writeDelimited(b1); - - ByteBuf b2 = Unpooled.buffer(entrySize); - TestBuffer.fillByteBuf(b2, 0xfedefede); - offset2 = writer.writeDelimited(b2); - writer.flush(); - } - - try (LogReader reader = new DirectReader(1234, logFilename(ledgerDir, 1234), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - ByteBuf bbread = reader.readEntryAt(offset1); - try { - assertThat(bbread.readableBytes(), equalTo(entrySize)); - while (bbread.readableBytes() >= Integer.BYTES) { - assertThat(bbread.readInt(), equalTo(0xfeedfeed)); - } - assertThat(bbread.readableBytes(), equalTo(0)); - } finally { - bbread.release(); - } - - bbread = reader.readEntryAt(offset2); - try { - assertThat(bbread.readableBytes(), equalTo(entrySize)); - while (bbread.readableBytes() >= Integer.BYTES) { - assertThat(bbread.readInt(), equalTo(0xfedefede)); - } - assertThat(bbread.readableBytes(), equalTo(0)); - } finally { - bbread.release(); - } - } - } - - private static void writeFileWithPattern(File directory, int logId, - int pattern, int blockIncrement, int fileSize) throws Exception { - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(logId, logFilename(directory, logId), - fileSize, MoreExecutors.newDirectExecutorService(), - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - - for (int written = 0; written < fileSize; written += Buffer.ALIGNMENT) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT); - TestBuffer.fillByteBuf(bb, pattern); - writer.writeAt(written, bb); - bb.release(); - pattern += blockIncrement; - } - writer.flush(); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectWriter.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectWriter.java deleted file mode 100644 index d8974147747..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectWriter.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.apache.bookkeeper.bookie.storage.directentrylogger.DirectEntryLogger.logFilename; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import com.google.common.util.concurrent.MoreExecutors; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import org.apache.bookkeeper.common.util.nativeio.NativeIO; -import org.apache.bookkeeper.common.util.nativeio.NativeIOException; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - -/** - * TestDirectWriter. - */ -public class TestDirectWriter { - private static final Slogger slog = Slogger.CONSOLE; - - private final TmpDirs tmpDirs = new TmpDirs(); - private final ExecutorService writeExecutor = Executors.newSingleThreadExecutor(); - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - writeExecutor.shutdownNow(); - } - - @Test(expected = IllegalArgumentException.class) - public void testWriteAtAlignment() throws Exception { - File ledgerDir = tmpDirs.createNew("writeAlignment", "logs"); - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(5678, logFilename(ledgerDir, 5678), - 1 << 24, writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT); - TestBuffer.fillByteBuf(bb, 0xdededede); - writer.writeAt(1234, bb); - writer.flush(); - } - } - - @Test(expected = IllegalArgumentException.class) - public void testWriteAlignmentSize() throws Exception { - File ledgerDir = tmpDirs.createNew("writeAlignment", "logs"); - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(5678, logFilename(ledgerDir, 5678), 1 << 24, writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - ByteBuf bb = Unpooled.buffer(123); - TestBuffer.fillByteBuf(bb, 0xdededede); - writer.writeAt(0, bb); - writer.flush(); - } - } - - @Test - public void testWriteAlignedNotAtStart() throws Exception { - File ledgerDir = tmpDirs.createNew("writeAlignment", "logs"); - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(5678, logFilename(ledgerDir, 5678), 1 << 24, writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT); - TestBuffer.fillByteBuf(bb, 0xdededede); - writer.writeAt(Buffer.ALIGNMENT * 2, bb); - writer.flush(); - } - } - - - @Test(timeout = 10000) - public void testFlushingWillWaitForBuffer() throws Exception { - File ledgerDir = tmpDirs.createNew("writeFailFailsFlush", "logs"); - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, - Buffer.ALIGNMENT, 1); // only one buffer available, so we can't flush in bg - LogWriter writer = new DirectWriter(5678, logFilename(ledgerDir, 5678), 1 << 24, writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT / 2); - TestBuffer.fillByteBuf(bb, 0xdededede); - writer.writeDelimited(bb); - writer.flush(); - } - } - - @Test(expected = IOException.class) - public void testWriteFailFailsFlush() throws Exception { - File ledgerDir = tmpDirs.createNew("writeFailFailsFlush", "logs"); - NativeIO io = new NativeIOImpl() { - boolean failed = false; - @Override - public int pwrite(int fd, long pointer, int count, long offset) throws NativeIOException { - synchronized (this) { - if (!failed) { - failed = true; - throw new NativeIOException("fail for test"); - } - } - return super.pwrite(fd, pointer, count, offset); - } - }; - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(5678, logFilename(ledgerDir, 5678), 1 << 24, writeExecutor, - buffers, io, Slogger.CONSOLE)) { - for (int i = 0; i < 10; i++) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT / 2); - TestBuffer.fillByteBuf(bb, 0xdededede); - writer.writeDelimited(bb); - } - writer.flush(); - } - } - - @Test(expected = IOException.class) - public void testWriteAtFailFailsFlush() throws Exception { - File ledgerDir = tmpDirs.createNew("writeFailFailsFlush", "logs"); - NativeIO io = new NativeIOImpl() { - boolean failed = false; - @Override - public int pwrite(int fd, long pointer, int count, long offset) throws NativeIOException { - synchronized (this) { - if (!failed) { - failed = true; - throw new NativeIOException("fail for test"); - } - } - return super.pwrite(fd, pointer, count, offset); - } - }; - - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 14, 8); - LogWriter writer = new DirectWriter(5678, logFilename(ledgerDir, 5678), 1 << 24, writeExecutor, - buffers, io, Slogger.CONSOLE)) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT); - TestBuffer.fillByteBuf(bb, 0xdededede); - writer.writeAt(0, bb); - writer.flush(); - } - } - - @Test - public void testWriteWithPadding() throws Exception { - File ledgerDir = tmpDirs.createNew("paddingWrite", "logs"); - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 14, 8); - LogWriter writer = new DirectWriter(5678, logFilename(ledgerDir, 5678), 1 << 24, writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT); - TestBuffer.fillByteBuf(bb, 0xdededede); - bb.writerIndex(123); - writer.writeDelimited(bb); - writer.flush(); - } - - ByteBuf contents = readIntoByteBuf(ledgerDir, 5678); - assertThat(contents.readInt(), equalTo(123)); - for (int i = 0; i < 123; i++) { - assertThat(contents.readByte(), equalTo((byte) 0xde)); - } - for (int i = 0; i < Buffer.ALIGNMENT - (123 + Integer.BYTES); i++) { - assertThat(contents.readByte(), equalTo(Buffer.PADDING_BYTE)); - } - while (contents.isReadable()) { - assertThat((int) contents.readByte(), equalTo(0)); - } - } - - @Test - public void testWriteBlocksFlush() throws Exception { - ExecutorService flushExecutor = Executors.newSingleThreadExecutor(); - try { - File ledgerDir = tmpDirs.createNew("blockWrite", "logs"); - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 14, 8); - LogWriter writer = new DirectWriter(1234, logFilename(ledgerDir, 1234), - 1 << 24, writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - CompletableFuture blocker = new CompletableFuture<>(); - writeExecutor.submit(() -> { - blocker.join(); - return null; - }); - ByteBuf bb = Unpooled.buffer(4096); - TestBuffer.fillByteBuf(bb, 0xdeadbeef); - writer.writeAt(0, bb); - Future f = flushExecutor.submit(() -> { - writer.flush(); - return null; - }); - Thread.sleep(100); - assertThat(f.isDone(), equalTo(false)); - blocker.complete(null); - f.get(); - } - ByteBuf contents = readIntoByteBuf(ledgerDir, 1234); - for (int i = 0; i < 4096 / Integer.BYTES; i++) { - assertThat(contents.readInt(), equalTo(0xdeadbeef)); - } - if (contents.readableBytes() > 0) { // linux-only: fallocate will preallocate file - while (contents.isReadable()) { - assertThat((int) contents.readByte(), equalTo(0)); - } - } - } finally { - flushExecutor.shutdownNow(); - } - } - - @Test(expected = IOException.class) - public void testFailsToOpen() throws Exception { - File ledgerDir = tmpDirs.createNew("failOpen", "logs"); - ledgerDir.delete(); - - BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 14, 8); - try { - new DirectWriter(1234, logFilename(ledgerDir, 1234), - 1 << 30, MoreExecutors.newDirectExecutorService(), - buffers, new NativeIOImpl(), Slogger.CONSOLE); - } finally { - buffers.close(); - } - } - - @Test - public void fallocateNotAvailable() throws Exception { - File ledgerDir = tmpDirs.createNew("fallocUnavailable", "logs"); - NativeIO nativeIO = new NativeIOImpl() { - @Override - public int fallocate(int fd, int mode, long offset, long len) - throws NativeIOException { - throw new NativeIOException("pretending I'm a mac"); - } - }; - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 14, 8); - LogWriter writer = new DirectWriter(3456, logFilename(ledgerDir, 3456), - 1 << 24, writeExecutor, - buffers, nativeIO, Slogger.CONSOLE)) { - ByteBuf bb = Unpooled.buffer(Buffer.ALIGNMENT); - TestBuffer.fillByteBuf(bb, 0xdeadbeef); - - writer.writeAt(0, bb); - writer.flush(); - } - - // should be 0xdeadbeef until the end of the file - ByteBuf contents = readIntoByteBuf(ledgerDir, 3456); - assertThat(contents.readableBytes(), equalTo(Buffer.ALIGNMENT)); - while (contents.isReadable()) { - assertThat(contents.readInt(), equalTo(0xdeadbeef)); - } - } - - @Test - public void testWriteAtIntLimit() throws Exception { - File ledgerDir = tmpDirs.createNew("intLimit", "logs"); - - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, 1 << 14, 8); - LogWriter writer = new DirectWriter(3456, logFilename(ledgerDir, 3456), - (long) Integer.MAX_VALUE + (Buffer.ALIGNMENT * 100), - writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - ByteBuf b1 = Unpooled.buffer(Buffer.ALIGNMENT - (Integer.BYTES * 2) - 1); - TestBuffer.fillByteBuf(b1, 0xdeadbeef); - - long finalSeekablePosition = Integer.MAX_VALUE & ~(Buffer.ALIGNMENT - 1); - writer.position(finalSeekablePosition); - long offset = writer.writeDelimited(b1); - assertThat(offset, equalTo(finalSeekablePosition + Integer.BYTES)); - assertThat(writer.position(), equalTo((long) Integer.MAX_VALUE - Integer.BYTES)); - - offset = writer.writeDelimited(b1); - assertThat(offset, equalTo((long) Integer.MAX_VALUE)); - - writer.flush(); - - try { - writer.writeDelimited(b1); - Assert.fail("Shouldn't be possible, we've gone past MAX_INT"); - } catch (IOException ioe) { - // expected - } - } - - } - - static ByteBuf readIntoByteBuf(File directory, int logId) throws Exception { - byte[] bytes = new byte[1024]; - File file = new File(DirectEntryLogger.logFilename(directory, logId)); - slog.kv("filename", file.toString()).info("reading in"); - ByteBuf byteBuf = Unpooled.buffer((int) file.length()); - try (FileInputStream is = new FileInputStream(file)) { - int bytesRead = is.read(bytes); - while (bytesRead > 0) { - byteBuf.writeBytes(bytes, 0, bytesRead); - bytesRead = is.read(bytes); - } - } - - assertThat(byteBuf.readableBytes(), equalTo((int) file.length())); - return byteBuf; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestEntryLogIds.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestEntryLogIds.java deleted file mode 100644 index 092583b08f6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestEntryLogIds.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.logIdFromLocation; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.makeEntry; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newDirsManager; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newLegacyEntryLogger; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import java.io.File; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.storage.EntryLogIds; -import org.apache.bookkeeper.bookie.storage.EntryLogger; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.bookkeeper.util.LedgerDirUtil; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.After; -import org.junit.Test; - -/** - * TestEntryLogIds. - */ -public class TestEntryLogIds { - private static final Slogger slog = Slogger.CONSOLE; - - private final TmpDirs tmpDirs = new TmpDirs(); - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - } - - @Test - public void testNoStomping() throws Exception { - File ledgerDir = tmpDirs.createNew("entryLogIds", "ledgers"); - - int highestSoFar = -1; - try (EntryLogger legacy = newLegacyEntryLogger(1024, ledgerDir)) { - ByteBuf e1 = makeEntry(1L, 1L, 2048); - long loc1 = legacy.addEntry(1L, e1); - int logId1 = logIdFromLocation(loc1); - - ByteBuf e2 = makeEntry(1L, 2L, 2048); - long loc2 = legacy.addEntry(1L, e2); - int logId2 = logIdFromLocation(loc2); - assertThat(logId2, greaterThan(logId1)); - highestSoFar = logId2; - } - - EntryLogIds ids = new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - int logId3 = ids.nextId(); - assertThat(logId3, greaterThan(highestSoFar)); - touchLog(ledgerDir, logId3); - highestSoFar = logId3; - - int logId4 = ids.nextId(); - assertThat(logId4, greaterThan(highestSoFar)); - touchLog(ledgerDir, logId4); - highestSoFar = logId4; - - try (EntryLogger legacy = newLegacyEntryLogger(1024, ledgerDir)) { - ByteBuf e1 = makeEntry(1L, 1L, 2048); - long loc5 = legacy.addEntry(1L, e1); - int logId5 = logIdFromLocation(loc5); - assertThat(logId5, greaterThan(highestSoFar)); - - ByteBuf e2 = makeEntry(1L, 2L, 2048); - long loc6 = legacy.addEntry(1L, e2); - int logId6 = logIdFromLocation(loc6); - assertThat(logId6, greaterThan(logId5)); - } - } - - @Test - public void testNoStompingDirectStartsFirst() throws Exception { - File ledgerDir = tmpDirs.createNew("entryLogIds", "ledgers"); - - int highestSoFar = -1; - EntryLogIds ids = new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - int logId1 = ids.nextId(); - assertThat(logId1, greaterThan(highestSoFar)); - touchLog(ledgerDir, logId1); - highestSoFar = logId1; - - try (EntryLogger legacy = newLegacyEntryLogger(1024, ledgerDir)) { - ByteBuf e1 = makeEntry(1L, 1L, 2048); - long loc2 = legacy.addEntry(1L, e1); - int logId2 = logIdFromLocation(loc2); - assertThat(logId2, greaterThan(highestSoFar)); - highestSoFar = logId2; - - ByteBuf e2 = makeEntry(1L, 2L, 2048); - long loc3 = legacy.addEntry(1L, e2); - int logId3 = logIdFromLocation(loc3); - assertThat(logId3, greaterThan(logId2)); - highestSoFar = logId3; - } - - // reinitialize to pick up legacy - ids = new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - int logId4 = ids.nextId(); - assertThat(logId4, greaterThan(highestSoFar)); - touchLog(ledgerDir, logId4); - highestSoFar = logId4; - } - - @Test - public void testIdGenerator() throws Exception { - File base = tmpDirs.createNew("entryLogIds", "ledgers"); - File ledgerDir1 = new File(base, "l1"); - File ledgerDir2 = new File(base, "l2"); - File ledgerDir3 = new File(base, "l3"); - File ledgerDir4 = new File(base, "l4"); - ledgerDir1.mkdir(); - ledgerDir2.mkdir(); - ledgerDir3.mkdir(); - ledgerDir4.mkdir(); - - //case 1: use root ledgerDirsManager - LedgerDirsManager ledgerDirsManager = newDirsManager(ledgerDir1, ledgerDir2); - EntryLogIds ids1 = new EntryLogIdsImpl(ledgerDirsManager, slog); - for (int i = 0; i < 10; i++) { - int logId = ids1.nextId(); - File log1 = new File(ledgerDir1 + "/current", logId + ".log"); - log1.createNewFile(); - assertEquals(logId, i); - } - - EntryLogIds ids2 = new EntryLogIdsImpl(ledgerDirsManager, slog); - for (int i = 0; i < 10; i++) { - int logId = ids2.nextId(); - assertEquals(logId, 10 + i); - } - - // case 2: new LedgerDirsManager for per directory - LedgerDirsManager ledgerDirsManager3 = newDirsManager(ledgerDir3); - LedgerDirsManager ledgerDirsManager4 = newDirsManager(ledgerDir4); - EntryLogIds ids3 = new EntryLogIdsImpl(ledgerDirsManager3, slog); - for (int i = 0; i < 10; i++) { - int logId = ids3.nextId(); - File log1 = new File(ledgerDir3 + "/current", logId + ".log"); - log1.createNewFile(); - assertEquals(logId, i); - } - - EntryLogIds ids4 = new EntryLogIdsImpl(ledgerDirsManager4, slog); - for (int i = 0; i < 10; i++) { - int logId = ids4.nextId(); - assertEquals(logId, i); - } - } - - @Test - public void testMultiDirectory() throws Exception { - File base = tmpDirs.createNew("entryLogIds", "ledgers"); - File ledgerDir1 = new File(base, "l1"); - File ledgerDir2 = new File(base, "l2"); - File ledgerDir3 = new File(base, "l3"); - - int highestSoFar = -1; - try (EntryLogger legacy = newLegacyEntryLogger(1024, ledgerDir1, ledgerDir2, ledgerDir3)) { - ByteBuf e1 = makeEntry(1L, 1L, 2048); - long loc1 = legacy.addEntry(1L, e1); - int logId1 = logIdFromLocation(loc1); - assertThat(logId1, greaterThan(highestSoFar)); - highestSoFar = logId1; - - ByteBuf e2 = makeEntry(1L, 2L, 2048); - long loc2 = legacy.addEntry(1L, e2); - int logId2 = logIdFromLocation(loc2); - assertThat(logId2, greaterThan(highestSoFar)); - highestSoFar = logId2; - - ByteBuf e3 = makeEntry(1L, 3L, 2048); - long loc3 = legacy.addEntry(1L, e3); - int logId3 = logIdFromLocation(loc3); - assertThat(logId3, greaterThan(highestSoFar)); - highestSoFar = logId3; - } - - EntryLogIds ids = new EntryLogIdsImpl(newDirsManager(ledgerDir1, ledgerDir2, ledgerDir3), slog); - int logId4 = ids.nextId(); - assertThat(logId4, greaterThan(highestSoFar)); - touchLog(ledgerDir2, logId4); - highestSoFar = logId4; - - try (EntryLogger legacy = newLegacyEntryLogger(1024, ledgerDir1, ledgerDir2, ledgerDir3)) { - ByteBuf e1 = makeEntry(1L, 1L, 2048); - long loc5 = legacy.addEntry(1L, e1); - int logId5 = logIdFromLocation(loc5); - assertThat(logId5, greaterThan(highestSoFar)); - highestSoFar = logId5; - } - } - - @Test - public void testWrapAround() throws Exception { - File ledgerDir = tmpDirs.createNew("entryLogIds", "ledgers"); - new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - touchLog(ledgerDir, Integer.MAX_VALUE - 1); - - EntryLogIds ids = new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - int logId = ids.nextId(); - assertThat(logId, equalTo(0)); - } - - @Test - public void testCompactingLogsNotConsidered() throws Exception { - // if there is a process restart, all "compacting" logs will be deleted - // so their IDs are safe to reuse. Even in the case of two processes acting - // the directory concurrently, the transactional rename will prevent data - // loss. - File ledgerDir = tmpDirs.createNew("entryLogIds", "ledgers"); - new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - touchLog(ledgerDir, 123); - touchCompacting(ledgerDir, 129); - - EntryLogIds ids = new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - int logId = ids.nextId(); - assertThat(logId, equalTo(124)); - } - - @Test - public void testCompactedLogsConsidered() throws Exception { - File ledgerDir = tmpDirs.createNew("entryLogIds", "ledgers"); - new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - touchLog(ledgerDir, 123); - touchCompacted(ledgerDir, 129, 123); - - EntryLogIds ids = new EntryLogIdsImpl(newDirsManager(ledgerDir), slog); - int logId = ids.nextId(); - assertThat(logId, equalTo(130)); - } - - - @Test - public void testGapSelection() throws Exception { - assertEquals(LedgerDirUtil.findLargestGap(Lists.newArrayList()), Pair.of(0, Integer.MAX_VALUE)); - assertEquals(LedgerDirUtil.findLargestGap(Lists.newArrayList(0)), - Pair.of(1, Integer.MAX_VALUE)); - assertEquals(LedgerDirUtil.findLargestGap(Lists.newArrayList(1, 2, 3, 4, 5, 6)), - Pair.of(7, Integer.MAX_VALUE)); - assertEquals(LedgerDirUtil.findLargestGap(Lists.newArrayList(Integer.MAX_VALUE)), - Pair.of(0, Integer.MAX_VALUE)); - assertEquals(LedgerDirUtil.findLargestGap(Lists.newArrayList(Integer.MAX_VALUE / 2)), - Pair.of(0, Integer.MAX_VALUE / 2)); - assertEquals(LedgerDirUtil.findLargestGap(Lists.newArrayList(Integer.MAX_VALUE / 2 - 1)), - Pair.of(Integer.MAX_VALUE / 2, Integer.MAX_VALUE)); - } - - private static void touchLog(File ledgerDir, int logId) throws Exception { - assertThat(DirectEntryLogger.logFile(new File(ledgerDir, "current"), logId).createNewFile(), - equalTo(true)); - } - - private static void touchCompacting(File ledgerDir, int logId) throws Exception { - assertThat(DirectCompactionEntryLog.compactingFile(new File(ledgerDir, "current"), logId).createNewFile(), - equalTo(true)); - } - - private static void touchCompacted(File ledgerDir, int newLogId, int compactedLogId) throws Exception { - assertThat(DirectCompactionEntryLog.compactedFile(new File(ledgerDir, "current"), newLogId, compactedLogId) - .createNewFile(), equalTo(true)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestMetadata.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestMetadata.java deleted file mode 100644 index 4aafd18ba4e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestMetadata.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.apache.bookkeeper.bookie.storage.directentrylogger.DirectEntryLogger.logFilename; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.io.File; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.apache.bookkeeper.bookie.EntryLogMetadata; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.junit.After; -import org.junit.Test; - -public class TestMetadata { - private static final Slogger slog = Slogger.CONSOLE; - private final OpStatsLogger opLogger = NullStatsLogger.INSTANCE.getOpStatsLogger("null"); - - private final TmpDirs tmpDirs = new TmpDirs(); - private final ExecutorService writeExecutor = Executors.newSingleThreadExecutor(); - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - writeExecutor.shutdownNow(); - } - - @Test - public void testReadMetaFromHeader() throws Exception { - File ledgerDir = tmpDirs.createNew("writeMetadataBeforeFsync", "logs"); - int logId = 5678; - try (BufferPool buffers = new BufferPool(new NativeIOImpl(), ByteBufAllocator.DEFAULT, Buffer.ALIGNMENT, 8); - LogWriter writer = new DirectWriter(logId, logFilename(ledgerDir, logId), - 1 << 24, writeExecutor, - buffers, new NativeIOImpl(), Slogger.CONSOLE)) { - long offset = 4096L; - writer.position(offset); - EntryLogMetadata entryLogMetadata = new EntryLogMetadata(logId); - entryLogMetadata.addLedgerSize(1, 10); - entryLogMetadata.addLedgerSize(2, 11); - LogMetadata.write(writer, entryLogMetadata, ByteBufAllocator.DEFAULT); - try (LogReader reader = new DirectReader(logId, logFilename(ledgerDir, logId), - ByteBufAllocator.DEFAULT, - new NativeIOImpl(), Buffer.ALIGNMENT, - 1 << 20, opLogger)) { - ByteBuf header = reader.readBufferAt(0, Header.LOGFILE_LEGACY_HEADER_SIZE); - assertThat(Header.HEADER_V1, equalTo(Header.extractVersion(header))); - assertThat(offset, equalTo(Header.extractLedgerMapOffset(header))); - assertThat(2, equalTo(Header.extractLedgerCount(header))); - } - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestTransactionalEntryLogCompactor.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestTransactionalEntryLogCompactor.java deleted file mode 100644 index 86d760d4598..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestTransactionalEntryLogCompactor.java +++ /dev/null @@ -1,609 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.directentrylogger; - -import static org.apache.bookkeeper.bookie.TransactionalEntryLogCompactor.COMPACTED_SUFFIX; -import static org.apache.bookkeeper.bookie.TransactionalEntryLogCompactor.COMPACTING_SUFFIX; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.assertEntryEquals; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.logIdFromLocation; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.makeEntry; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newDirectEntryLogger; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newDirsManager; -import static org.apache.bookkeeper.bookie.storage.EntryLogTestUtils.newLegacyEntryLogger; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.not; - -import com.google.common.util.concurrent.MoreExecutors; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.apache.bookkeeper.bookie.EntryLocation; -import org.apache.bookkeeper.bookie.EntryLogMetadata; -import org.apache.bookkeeper.bookie.MockLedgerStorage; -import org.apache.bookkeeper.bookie.TransactionalEntryLogCompactor; -import org.apache.bookkeeper.bookie.storage.CompactionEntryLog; -import org.apache.bookkeeper.bookie.storage.EntryLogScanner; -import org.apache.bookkeeper.bookie.storage.EntryLogger; -import org.apache.bookkeeper.common.util.nativeio.NativeIOImpl; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.slogger.Slogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.junit.After; -import org.junit.Test; - -/** - * TestTransactionalEntryLogCompactor. - */ -public class TestTransactionalEntryLogCompactor { - private static final Slogger slog = Slogger.CONSOLE; - - private final TmpDirs tmpDirs = new TmpDirs(); - private static final long deadLedger = 1L; - private static final long liveLedger = 2L; - - @After - public void cleanup() throws Exception { - tmpDirs.cleanup(); - } - - @Test - public void testHappyCase() throws Exception { - File ledgerDir = tmpDirs.createNew("compactHappyCase", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData(ledgerDir); - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - assertThat(meta.containsLedger(deadLedger), equalTo(true)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + 1000 + (Integer.BYTES * 2))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(true)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(1)); - EntryLocation loc = ledgerStorage.getUpdatedLocations().get(0); - - long compactedLogId = logIdFromLocation(loc.getLocation()); - assertThat(compactedLogId, not(equalTo(logId))); - assertThat(loc.getLedger(), equalTo(liveLedger)); - assertThat(loc.getEntry(), equalTo(2L)); - - meta = entryLogger.getEntryLogMetadata(compactedLogId); - assertThat(meta.containsLedger(deadLedger), equalTo(false)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + Integer.BYTES)); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - ByteBuf bb = entryLogger.readEntry(loc.getLedger(), loc.getEntry(), loc.getLocation()); - assertEntryEquals(bb, makeEntry(liveLedger, 2L, 1000, (byte) 0xfa)); - assertThat(entryLogger.incompleteCompactionLogs(), empty()); - } - } - - @Test - public void testHappyCase1000() throws Exception { - File ledgerDir = tmpDirs.createNew("compactHappyCase1000", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData1000(ledgerDir); - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - assertThat(meta.containsLedger(deadLedger), equalTo(true)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo((1000L + Integer.BYTES) * 1000 * 2)); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(true)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(1000)); - long compactedLogId = -1; - for (int i = 0; i < 1000; i++) { - EntryLocation loc = ledgerStorage.getUpdatedLocations().get(i); - compactedLogId = logIdFromLocation(loc.getLocation()); - assertThat(compactedLogId, not(equalTo(logId))); - assertThat(loc.getLedger(), equalTo(liveLedger)); - assertThat(loc.getEntry(), equalTo(Long.valueOf(i))); - - ByteBuf bb = entryLogger.readEntry(loc.getLedger(), loc.getEntry(), loc.getLocation()); - assertEntryEquals(bb, makeEntry(liveLedger, i, 1000, (byte) (0xfa + i))); - } - - meta = entryLogger.getEntryLogMetadata(compactedLogId); - assertThat(meta.containsLedger(deadLedger), equalTo(false)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo((1000L + Integer.BYTES) * 1000)); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - assertThat(entryLogger.incompleteCompactionLogs(), empty()); - } - } - - @Test - public void testScanFail() throws Exception { - File ledgerDir = tmpDirs.createNew("compactScanFail", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData(ledgerDir); - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - try (EntryLogger entryLogger = newDirectEntryLoggerFailAdd(ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - assertThat(meta.containsLedger(deadLedger), equalTo(true)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + 1000 + (Integer.BYTES * 2))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(false)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(0)); - assertThat(entryLogger.incompleteCompactionLogs(), empty()); - - assertThat(compactingFiles(curDir), empty()); - assertThat(compactedFiles(curDir), empty()); - } - } - - @Test - public void testScanFailNoAbortAndContinue() throws Exception { - File ledgerDir = tmpDirs.createNew("compactScanFail", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData(ledgerDir); - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - try (EntryLogger entryLogger = newDirectEntryLoggerFailAddNoAbort(ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - assertThat(meta.containsLedger(deadLedger), equalTo(true)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + 1000 + (Integer.BYTES * 2))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(false)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(0)); - assertThat(compactingFiles(curDir).size(), equalTo(1)); - assertThat(compactedFiles(curDir), empty()); - } - - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - compactor.cleanUpAndRecover(); - assertThat(compactingFiles(curDir), empty()); - assertThat(compactedFiles(curDir), empty()); - - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(true)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(1)); - - EntryLocation loc = ledgerStorage.getUpdatedLocations().get(0); - - long compactedLogId = logIdFromLocation(loc.getLocation()); - assertThat(compactedLogId, not(equalTo(logId))); - assertThat(loc.getLedger(), equalTo(liveLedger)); - assertThat(loc.getEntry(), equalTo(2L)); - } - } - - @Test - public void testFlushFail() throws Exception { - File ledgerDir = tmpDirs.createNew("compactScanFail", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData(ledgerDir); - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - try (EntryLogger entryLogger = newDirectEntryLoggerFailFlush(ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - assertThat(meta.containsLedger(deadLedger), equalTo(true)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + 1000 + (Integer.BYTES * 2))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(false)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(0)); - assertThat(entryLogger.incompleteCompactionLogs(), empty()); - - assertThat(compactingFiles(curDir), empty()); - assertThat(compactedFiles(curDir), empty()); - } - } - - @Test - public void testMarkCompactFailNoAbort() throws Exception { - File ledgerDir = tmpDirs.createNew("compactScanFail", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData(ledgerDir); - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - try (EntryLogger entryLogger = newDirectEntryLoggerFailMarkCompactedNoAbort(ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - assertThat(meta.containsLedger(deadLedger), equalTo(true)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + 1000 + (Integer.BYTES * 2))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(false)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(0)); - assertThat(compactingFiles(curDir), empty()); - assertThat(compactedFiles(curDir), hasSize(1)); - } - - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - assertThat(entryLogger.logExists(logId), equalTo(true)); - CompletableFuture removedId = new CompletableFuture<>(); - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> removedId.complete(removedLogId)); - compactor.cleanUpAndRecover(); - assertThat(compactingFiles(curDir), empty()); - assertThat(compactedFiles(curDir), empty()); - - assertThat(removedId.isDone(), equalTo(true)); - assertThat(removedId.get(), equalTo(logId)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(1)); - - EntryLocation loc = ledgerStorage.getUpdatedLocations().get(0); - - long compactedLogId = logIdFromLocation(loc.getLocation()); - assertThat(compactedLogId, not(equalTo(logId))); - assertThat(loc.getLedger(), equalTo(liveLedger)); - assertThat(loc.getEntry(), equalTo(2L)); - - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(compactedLogId); - assertThat(meta.containsLedger(deadLedger), equalTo(false)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + Integer.BYTES)); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - ByteBuf bb = entryLogger.readEntry(loc.getLedger(), loc.getEntry(), loc.getLocation()); - assertEntryEquals(bb, makeEntry(liveLedger, 2L, 1000, (byte) 0xfa)); - assertThat(entryLogger.incompleteCompactionLogs(), empty()); - } - } - - @Test - public void testIndexFail() throws Exception { - File ledgerDir = tmpDirs.createNew("compactScanFail", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData(ledgerDir); - MockLedgerStorage ledgerStorageFailFlush = new MockLedgerStorage() { - @Override - public void flushEntriesLocationsIndex() throws IOException { - throw new IOException("fail on flush"); - } - }; - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorageFailFlush, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - assertThat(meta.containsLedger(deadLedger), equalTo(true)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + 1000 + (Integer.BYTES * 2))); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(false)); - - assertThat(ledgerStorageFailFlush.getUpdatedLocations(), hasSize(1)); - assertThat(compactingFiles(curDir), empty()); - assertThat(compactedFiles(curDir), hasSize(1)); - } - - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - CompletableFuture removedId = new CompletableFuture<>(); - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> removedId.complete(removedLogId)); - assertThat(entryLogger.logExists(logId), equalTo(true)); - compactor.cleanUpAndRecover(); - assertThat(compactingFiles(curDir), empty()); - assertThat(compactedFiles(curDir), empty()); - - assertThat(removedId.isDone(), equalTo(true)); - assertThat(removedId.get(), equalTo(logId)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(1)); - - EntryLocation loc = ledgerStorage.getUpdatedLocations().get(0); - - long compactedLogId = logIdFromLocation(loc.getLocation()); - assertThat(compactedLogId, not(equalTo(logId))); - assertThat(loc.getLedger(), equalTo(liveLedger)); - assertThat(loc.getEntry(), equalTo(2L)); - - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(compactedLogId); - assertThat(meta.containsLedger(deadLedger), equalTo(false)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo(1000L + Integer.BYTES)); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - - ByteBuf bb = entryLogger.readEntry(loc.getLedger(), loc.getEntry(), loc.getLocation()); - assertEntryEquals(bb, makeEntry(liveLedger, 2L, 1000, (byte) 0xfa)); - assertThat(entryLogger.incompleteCompactionLogs(), empty()); - } - } - - @Test - public void testMetadataWritten() throws Exception { - File ledgerDir = tmpDirs.createNew("compactHappyCase", "ledgers"); - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - long logId = writeLogData1000(ledgerDir); - MockLedgerStorage ledgerStorage = new MockLedgerStorage(); - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - TransactionalEntryLogCompactor compactor = new TransactionalEntryLogCompactor( - new ServerConfiguration(), - entryLogger, - ledgerStorage, - (removedLogId) -> {}); - EntryLogMetadata meta = entryLogger.getEntryLogMetadata(logId); - meta.removeLedgerIf((ledgerId) -> ledgerId == deadLedger); - assertThat(compactor.compact(meta), equalTo(true)); - - assertThat(ledgerStorage.getUpdatedLocations(), hasSize(1000)); - long compactedLogId = logIdFromLocation( - ledgerStorage.getUpdatedLocations().get(0).getLocation()); - - meta = ((DirectEntryLogger) entryLogger).readEntryLogIndex(compactedLogId); - assertThat(meta.containsLedger(deadLedger), equalTo(false)); - assertThat(meta.containsLedger(liveLedger), equalTo(true)); - assertThat(meta.getTotalSize(), equalTo((1000L + Integer.BYTES) * 1000)); - assertThat(meta.getRemainingSize(), equalTo(meta.getTotalSize())); - } - } - - Set compactingFiles(File dir) throws Exception { - return Arrays.stream(dir.listFiles((f) -> f.getName().endsWith(COMPACTING_SUFFIX))) - .collect(Collectors.toSet()); - } - - Set compactedFiles(File dir) throws Exception { - return Arrays.stream(dir.listFiles((f) -> f.getName().endsWith(COMPACTED_SUFFIX))) - .collect(Collectors.toSet()); - } - - int writeLogData(File ledgerDir) throws Exception { - try (EntryLogger entryLogger = newLegacyEntryLogger(2 << 20, ledgerDir)) { - long loc1 = entryLogger.addEntry(deadLedger, makeEntry(deadLedger, 1L, 1000, (byte) 0xde)); - long loc2 = entryLogger.addEntry(liveLedger, makeEntry(liveLedger, 2L, 1000, (byte) 0xfa)); - assertThat(logIdFromLocation(loc1), equalTo(logIdFromLocation(loc2))); - return logIdFromLocation(loc2); - } - } - - int writeLogData1000(File ledgerDir) throws Exception { - try (EntryLogger entryLogger = newDirectEntryLogger(2 << 20, ledgerDir)) { - long loc1, loc2 = -1; - for (int i = 0; i < 1000; i++) { - loc1 = entryLogger.addEntry(deadLedger, makeEntry(deadLedger, i, 1000, (byte) (0xde + i))); - if (loc2 != -1) { - assertThat(logIdFromLocation(loc1), equalTo(logIdFromLocation(loc2))); - } - loc2 = entryLogger.addEntry(liveLedger, makeEntry(liveLedger, i, 1000, (byte) (0xfa + i))); - assertThat(logIdFromLocation(loc1), equalTo(logIdFromLocation(loc2))); - } - return logIdFromLocation(loc2); - } - } - - private static DirectEntryLogger newDirectEntryLoggerFailAdd(File ledgerDir) throws Exception { - return newDirectEntryLoggerCompactionOverride( - ledgerDir, - (cel) -> new CompactionEntryLogProxy(cel) { - @Override - public long addEntry(long ledgerId, ByteBuf entry) throws IOException { - throw new IOException("Don't allow adds"); - } - }); - } - - private static DirectEntryLogger newDirectEntryLoggerFailAddNoAbort(File ledgerDir) throws Exception { - return newDirectEntryLoggerCompactionOverride( - ledgerDir, - (cel) -> new CompactionEntryLogProxy(cel) { - @Override - public long addEntry(long ledgerId, ByteBuf entry) throws IOException { - throw new IOException("Don't allow adds"); - } - - @Override - public void abort() {} - }); - } - - private static DirectEntryLogger newDirectEntryLoggerFailFlush(File ledgerDir) throws Exception { - return newDirectEntryLoggerCompactionOverride( - ledgerDir, - (cel) -> new CompactionEntryLogProxy(cel) { - @Override - public void flush() throws IOException { - throw new IOException("No flushing"); - } - }); - } - - private static DirectEntryLogger newDirectEntryLoggerFailMarkCompactedNoAbort(File ledgerDir) throws Exception { - return newDirectEntryLoggerCompactionOverride( - ledgerDir, - (cel) -> new CompactionEntryLogProxy(cel) { - @Override - public void markCompacted() throws IOException { - super.markCompacted(); - throw new IOException("No compact"); - } - - @Override - public void abort() {} - }); - } - - private static DirectEntryLogger newDirectEntryLoggerCompactionOverride( - File ledgerDir, - Function override) throws Exception { - File curDir = new File(ledgerDir, "current"); - curDir.mkdirs(); - - return new DirectEntryLogger( - curDir, new EntryLogIdsImpl(newDirsManager(ledgerDir), slog), - new NativeIOImpl(), - ByteBufAllocator.DEFAULT, - MoreExecutors.newDirectExecutorService(), - MoreExecutors.newDirectExecutorService(), - 2 << 20, // max file size - 10 * 1024 * 1024, // max sane entry size - 1024 * 1024, // total write buffer size - 1024 * 1024, // total read buffer size - 4 * 1024, // read buffer size - 1, // numReadThreads - 300, // max fd cache time in seconds - slog, NullStatsLogger.INSTANCE) { - @Override - public CompactionEntryLog newCompactionLog(long logToCompact) throws IOException { - return override.apply(super.newCompactionLog(logToCompact)); - } - }; - } - - private static class CompactionEntryLogProxy implements CompactionEntryLog { - protected final CompactionEntryLog delegate; - - CompactionEntryLogProxy(CompactionEntryLog delegate) { - this.delegate = delegate; - } - - @Override - public long addEntry(long ledgerId, ByteBuf entry) throws IOException { - return delegate.addEntry(ledgerId, entry); - } - - @Override - public void scan(EntryLogScanner scanner) throws IOException { - delegate.scan(scanner); - } - - @Override - public void flush() throws IOException { - delegate.flush(); - } - - @Override - public void abort() { - delegate.abort(); - } - - @Override - public void markCompacted() throws IOException { - delegate.markCompacted(); - } - - @Override - public void makeAvailable() throws IOException { - delegate.makeAvailable(); - } - - @Override - public void finalizeAndCleanup() { - delegate.finalizeAndCleanup(); - } - - @Override - public long getDstLogId() { - return delegate.getDstLogId(); - } - - @Override - public long getSrcLogId() { - return delegate.getSrcLogId(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ArraySortGroupTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ArraySortGroupTest.java deleted file mode 100644 index 94ca14fd6cc..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ArraySortGroupTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertArrayEquals; - -import org.junit.Test; - -/** - * Unit test for {@link ArrayGroupSort}. - */ -public class ArraySortGroupTest { - - @Test - public void simple() { - long[] data = new long[] { // - 1, 2, 3, 4, // - 5, 6, 3, 1, // - 4, 8, 1, 2, // - 4, 5, 12, 10, // - 3, 3, 3, 3, // - 4, 3, 1, 2, // - 3, 3, 3, 3, // - }; - - long[] expectedSorted = new long[] { // - 1, 2, 3, 4, // - 3, 3, 3, 3, // - 3, 3, 3, 3, // - 4, 3, 1, 2, // - 4, 5, 12, 10, // - 4, 8, 1, 2, // - 5, 6, 3, 1, // - }; - - ArrayGroupSort.sort(data); - - assertArrayEquals(expectedSorted, data); - } - - @Test(expected = IllegalArgumentException.class) - public void arraySizeIsNotMultiple() { - ArrayGroupSort.sort(new long[] { 1, 2, 3, 4, 5 }); - } - - @Test(expected = IllegalArgumentException.class) - public void arraySizeIsShorterThanRequired() { - ArrayGroupSort.sort(new long[] { 1, 2 }); - } - - @Test - public void emptyArray() { - long[] data = new long[] {}; - - long[] expectedSorted = new long[] {}; - - ArrayGroupSort.sort(data); - - assertArrayEquals(expectedSorted, data); - } - - @Test - public void singleItem() { - long[] data = new long[] { 1, 2, 3, 4 }; - long[] expectedSorted = new long[] { 1, 2, 3, 4 }; - - ArrayGroupSort.sort(data); - - assertArrayEquals(expectedSorted, data); - } - - @Test - public void twoItems() { - long[] data = new long[] { 1, 2, 3, 4, 1, 1, 5, 5 }; - long[] expectedSorted = new long[] { 1, 1, 5, 5, 1, 2, 3, 4 }; - - ArrayGroupSort.sort(data); - - assertArrayEquals(expectedSorted, data); - } - - @Test - public void threeItems() { - long[] data = new long[] { 1, 2, 3, 4, 1, 1, 5, 5, 1, 0, 2, 1 }; - long[] expectedSorted = new long[] { 1, 0, 2, 1, 1, 1, 5, 5, 1, 2, 3, 4 }; - - ArrayGroupSort.sort(data); - - assertArrayEquals(expectedSorted, data); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionRollbackTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionRollbackTest.java deleted file mode 100644 index d7034a339c1..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionRollbackTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.Set; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieShell; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - - -/** - * Test for BookieShell convert-to-interleaved-storage command. - */ -@Slf4j -public class ConversionRollbackTest { - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - @Test - public void convertFromDbStorageToInterleaved() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - log.info("Using temp directory: {}", tmpDir); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DbLedgerStorage dbStorage = new DbLedgerStorage(); - dbStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - dbStorage.setCheckpointer(checkpointer); - dbStorage.setCheckpointSource(checkpointSource); - - // Insert some ledger & entries in the dbStorage - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - dbStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - dbStorage.setFenced(ledgerId); - - for (long entryId = 0; entryId < 10000; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - dbStorage.addEntry(entry); - } - } - - dbStorage.flush(); - dbStorage.shutdown(); - - // Run conversion tool - BookieShell shell = new BookieShell(); - shell.setConf(conf); - int res = shell.run(new String[] { "convert-to-interleaved-storage" }); - - Assert.assertEquals(0, res); - - // Verify that interleaved storage index has the same entries - InterleavedLedgerStorage interleavedStorage = new InterleavedLedgerStorage(); - interleavedStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - interleavedStorage.setCheckpointSource(checkpointSource); - interleavedStorage.setCheckpointer(checkpointer); - - Set ledgers = Sets.newTreeSet(interleavedStorage.getActiveLedgersInRange(0, Long.MAX_VALUE)); - Assert.assertEquals(Sets.newTreeSet(Lists.newArrayList(0L, 1L, 2L, 3L, 4L)), ledgers); - - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - Assert.assertEquals(true, interleavedStorage.isFenced(ledgerId)); - Assert.assertEquals("ledger-" + ledgerId, new String(interleavedStorage.readMasterKey(ledgerId))); - - for (long entryId = 0; entryId < 10000; entryId++) { - ByteBuf entry = Unpooled.buffer(1024); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ByteBuf result = interleavedStorage.getEntry(ledgerId, entryId); - Assert.assertEquals(entry, result); - } - } - - interleavedStorage.shutdown(); - FileUtils.forceDelete(tmpDir); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionTest.java deleted file mode 100644 index 2e6095dc115..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.Set; -import org.apache.bookkeeper.bookie.Bookie.NoLedgerException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieShell; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for BookieShell convert-to-db-storage command. - */ -public class ConversionTest { - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - @Test - public void test() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - System.out.println(tmpDir); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - InterleavedLedgerStorage interleavedStorage = new InterleavedLedgerStorage(); - interleavedStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - interleavedStorage.setCheckpointSource(checkpointSource); - interleavedStorage.setCheckpointer(checkpointer); - - // Insert some ledger & entries in the interleaved storage - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - interleavedStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - interleavedStorage.setFenced(ledgerId); - - for (long entryId = 0; entryId < 10000; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - interleavedStorage.addEntry(entry); - } - } - - interleavedStorage.flush(); - interleavedStorage.shutdown(); - - // Run conversion tool - BookieShell shell = new BookieShell(); - shell.setConf(conf); - int res = shell.run(new String[] { "convert-to-db-storage" }); - - Assert.assertEquals(0, res); - - // Verify that db index has the same entries - DbLedgerStorage dbStorage = new DbLedgerStorage(); - dbStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - dbStorage.setCheckpointer(checkpointer); - dbStorage.setCheckpointSource(checkpointSource); - - interleavedStorage = new InterleavedLedgerStorage(); - interleavedStorage.initialize(conf, null, ledgerDirsManager, - ledgerDirsManager, NullStatsLogger.INSTANCE, - UnpooledByteBufAllocator.DEFAULT); - interleavedStorage.setCheckpointSource(checkpointSource); - interleavedStorage.setCheckpointer(checkpointer); - - Set ledgers = Sets.newTreeSet(dbStorage.getActiveLedgersInRange(0, Long.MAX_VALUE)); - Assert.assertEquals(Sets.newTreeSet(Lists.newArrayList(0L, 1L, 2L, 3L, 4L)), ledgers); - - ledgers = Sets.newTreeSet(interleavedStorage.getActiveLedgersInRange(0, Long.MAX_VALUE)); - Assert.assertEquals(Sets.newTreeSet(), ledgers); - - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - Assert.assertEquals(true, dbStorage.isFenced(ledgerId)); - Assert.assertEquals("ledger-" + ledgerId, new String(dbStorage.readMasterKey(ledgerId))); - - for (long entryId = 0; entryId < 10000; entryId++) { - ByteBuf entry = Unpooled.buffer(1024); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ByteBuf result = dbStorage.getEntry(ledgerId, entryId); - Assert.assertEquals(entry, result); - result.release(); - - try { - interleavedStorage.getEntry(ledgerId, entryId); - Assert.fail("entry should not exist"); - } catch (NoLedgerException e) { - // Ok - } - } - } - - interleavedStorage.shutdown(); - dbStorage.shutdown(); - FileUtils.forceDelete(tmpDir); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageBookieTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageBookieTest.java deleted file mode 100644 index 4e31d8eeeb0..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageBookieTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; - -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit test for {@link DbLedgerStorageBookieTest}. - */ -public class DbLedgerStorageBookieTest extends BookKeeperClusterTestCase { - static final Logger LOG = LoggerFactory.getLogger(DbLedgerStorageBookieTest.class); - - public DbLedgerStorageBookieTest() { - super(1); - baseConf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - baseConf.setFlushInterval(60000); - baseConf.setGcWaitTime(60000); - - // Leave it empty to pickup default - baseConf.setProperty(DbLedgerStorage.WRITE_CACHE_MAX_SIZE_MB, ""); - - // Configure explicitly with a int object - baseConf.setProperty(DbLedgerStorage.READ_AHEAD_CACHE_MAX_SIZE_MB, 16); - } - - @Test - public void testRecoveryEmptyLedger() throws Exception { - LedgerHandle lh1 = bkc.createLedger(1, 1, DigestType.MAC, new byte[0]); - - // Force ledger close & recovery - LedgerHandle lh2 = bkc.openLedger(lh1.getId(), DigestType.MAC, new byte[0]); - - assertEquals(0, lh2.getLength()); - assertEquals(-1, lh2.getLastAddConfirmed()); - } - - @Test - public void testV2ReadWrite() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - LedgerHandle lh1 = bkc.createLedger(1, 1, DigestType.CRC32, new byte[0]); - lh1.addEntry("Foobar".getBytes()); - lh1.close(); - - LedgerHandle lh2 = bkc.openLedger(lh1.getId(), DigestType.CRC32, new byte[0]); - assertEquals(0, lh2.getLastAddConfirmed()); - assertEquals(new String(lh2.readEntries(0, 0).nextElement().getEntry()), - "Foobar"); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageIndexDirTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageIndexDirTest.java deleted file mode 100644 index 4cefc726b14..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageIndexDirTest.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.Arrays; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link DbLedgerStorage}. - */ -public class DbLedgerStorageIndexDirTest { - - private DbLedgerStorage storage; - private File tmpLedgerDir; - private File tmpIndexDir; - private static final String LOCATION_INDEX_SUB_PATH = "locations"; - private static final String METADATA_INDEX_SUB_PATH = "ledgers"; - - @Before - public void setup() throws Exception { - tmpLedgerDir = File.createTempFile("ledgerDir", ".dir"); - tmpLedgerDir.delete(); - tmpLedgerDir.mkdir(); - File curLedgerDir = BookieImpl.getCurrentDirectory(tmpLedgerDir); - BookieImpl.checkDirectoryStructure(curLedgerDir); - - tmpIndexDir = File.createTempFile("indexDir", ".dir"); - tmpIndexDir.delete(); - tmpIndexDir.mkdir(); - File curIndexDir = BookieImpl.getCurrentDirectory(tmpIndexDir); - BookieImpl.checkDirectoryStructure(curIndexDir); - - int gcWaitTime = 1000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - /** the testcase cover specify indexDir for the class {@link SingleDirectoryDbLedgerStorage} */ - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - conf.setProperty(DbLedgerStorage.WRITE_CACHE_MAX_SIZE_MB, 1); - conf.setProperty(DbLedgerStorage.MAX_THROTTLE_TIME_MILLIS, 1000); - conf.setLedgerDirNames(new String[]{tmpLedgerDir.toString()}); - conf.setIndexDirName(new String[]{tmpIndexDir.toString()}); - Bookie bookie = new TestBookieImpl(conf); - - storage = (DbLedgerStorage) bookie.getLedgerStorage(); - } - - @After - public void teardown() throws Exception { - storage.shutdown(); - tmpLedgerDir.delete(); - tmpIndexDir.delete(); - } - - public boolean hasIndexStructure(File tmpDir) { - File indexParentDir = BookieImpl.getCurrentDirectory(tmpDir); - String[] indexSubPaths = indexParentDir.list(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - if (LOCATION_INDEX_SUB_PATH.equals(name) || METADATA_INDEX_SUB_PATH.equals(name)) { - return true; - } - return false; - } - }); - - if (indexSubPaths.length == 0) { - return false; - } - long hasIndexPathCount = Arrays.stream(indexSubPaths).filter(isp -> { - String[] indexFiles = new File(indexParentDir, isp).list(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - if ("LOCK".equals(name) || "IDENTITY".equals(name) || "CURRENT".equals(name)) { - return true; - } - return false; - } - }); - if (indexFiles.length == 3) { - return true; - } - return false; - }).count(); - - if (hasIndexPathCount == indexSubPaths.length) { - return true; - } - return false; - } - - @Test - public void checkIndexNotExistsInLedgerDirStructure() { - // old logic bugfix - assertEquals(false, hasIndexStructure(tmpLedgerDir)); - } - - @Test - public void checkIndexDirectoryStructure() { - // index new logic - assertEquals(true, hasIndexStructure(tmpIndexDir)); - } - - @Test - public void simpleRegressionTest() throws Exception { - assertEquals(false, storage.ledgerExists(3)); - try { - storage.isFenced(3); - fail("should have failed"); - } catch (Bookie.NoLedgerException nle) { - // OK - } - assertEquals(false, storage.ledgerExists(3)); - try { - storage.setFenced(3); - fail("should have failed"); - } catch (Bookie.NoLedgerException nle) { - // OK - } - storage.setMasterKey(3, "key".getBytes()); - try { - storage.setMasterKey(3, "other-key".getBytes()); - fail("should have failed"); - } catch (IOException ioe) { - assertTrue(ioe.getCause() instanceof BookieException.BookieIllegalOpException); - } - // setting the same key is NOOP - storage.setMasterKey(3, "key".getBytes()); - assertEquals(true, storage.ledgerExists(3)); - assertEquals(true, storage.setFenced(3)); - assertEquals(true, storage.isFenced(3)); - assertEquals(false, storage.setFenced(3)); - - storage.setMasterKey(4, "key".getBytes()); - assertEquals(false, storage.isFenced(4)); - assertEquals(true, storage.ledgerExists(4)); - - assertEquals("key", new String(storage.readMasterKey(4))); - - assertEquals(Lists.newArrayList(4L, 3L), Lists.newArrayList(storage.getActiveLedgersInRange(0, 100))); - assertEquals(Lists.newArrayList(4L, 3L), Lists.newArrayList(storage.getActiveLedgersInRange(3, 100))); - assertEquals(Lists.newArrayList(3L), Lists.newArrayList(storage.getActiveLedgersInRange(0, 4))); - - // Add / read entries - ByteBuf entry = Unpooled.buffer(1024); - entry.writeLong(4); // ledger id - entry.writeLong(1); // entry id - entry.writeLong(0); // lac - entry.writeBytes("entry-1".getBytes()); - - assertEquals(false, ((DbLedgerStorage) storage).isFlushRequired()); - - assertEquals(1, storage.addEntry(entry)); - - assertEquals(true, ((DbLedgerStorage) storage).isFlushRequired()); - - // Read from write cache - assertTrue(storage.entryExists(4, 1)); - ByteBuf res = storage.getEntry(4, 1); - assertEquals(entry, res); - - storage.flush(); - - assertEquals(false, ((DbLedgerStorage) storage).isFlushRequired()); - - // Read from db - assertTrue(storage.entryExists(4, 1)); - res = storage.getEntry(4, 1); - assertEquals(entry, res); - - try { - storage.getEntry(4, 2); - fail("Should have thrown exception"); - } catch (Bookie.NoEntryException e) { - // ok - } - - ByteBuf entry2 = Unpooled.buffer(1024); - entry2.writeLong(4); // ledger id - entry2.writeLong(2); // entry id - entry2.writeLong(1); // lac - entry2.writeBytes("entry-2".getBytes()); - - storage.addEntry(entry2); - - // Read last entry in ledger - res = storage.getEntry(4, BookieProtocol.LAST_ADD_CONFIRMED); - assertEquals(entry2, res); - - // Read last add confirmed in ledger - assertEquals(1L, storage.getLastAddConfirmed(4)); - - ByteBuf entry3 = Unpooled.buffer(1024); - entry3.writeLong(4); // ledger id - entry3.writeLong(3); // entry id - entry3.writeLong(2); // lac - entry3.writeBytes("entry-3".getBytes()); - storage.addEntry(entry3); - - ByteBuf entry4 = Unpooled.buffer(1024); - entry4.writeLong(4); // ledger id - entry4.writeLong(4); // entry id - entry4.writeLong(3); // lac - entry4.writeBytes("entry-4".getBytes()); - storage.addEntry(entry4); - - res = storage.getEntry(4, 4); - assertEquals(entry4, res); - - assertEquals(3, storage.getLastAddConfirmed(4)); - - // Delete - assertEquals(true, storage.ledgerExists(4)); - storage.deleteLedger(4); - assertEquals(false, storage.ledgerExists(4)); - - // remove entries for ledger 4 from cache - storage.flush(); - - try { - storage.getEntry(4, 4); - fail("Should have thrown exception since the ledger was deleted"); - } catch (Bookie.NoLedgerException e) { - // ok - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageReadCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageReadCacheTest.java deleted file mode 100644 index 81ef7f9495c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageReadCacheTest.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage.READ_AHEAD_CACHE_BATCH_BYTES_SIZE; -import static org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage.READ_AHEAD_CACHE_BATCH_SIZE; -import static org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage.READ_AHEAD_CACHE_MAX_SIZE_MB; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.util.List; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.DefaultEntryLogger; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit test for {@link DbLedgerStorage}. - */ -public class DbLedgerStorageReadCacheTest { - private static final Logger LOGGER = LoggerFactory.getLogger(DbLedgerStorageReadCacheTest.class); - - @Test - public void chargeReadAheadCacheRegressionTest() { - TestDB testDB = new TestDB(); - try { - long readAheadCacheMaxSizeMb = 16L; - int readAheadCacheBatchSize = 1024; - long readAheadCacheBatchBytesSize = -1; - setup(testDB, readAheadCacheMaxSizeMb, readAheadCacheBatchSize, readAheadCacheBatchBytesSize); - SingleDirectoryDbLedgerStorage sdb = testDB.getStorage().getLedgerStorageList().get(0); - /** - * case1: currentReadAheadCount < readAheadCacheBatchSize - * currentReadAheadBytes < maxReadAheadBytesSize - * result: true - */ - int currentReadAheadCount = 1; - long currentReadAheadBytes = 1; - assertTrue(sdb.chargeReadAheadCache(currentReadAheadCount, currentReadAheadBytes)); - - /** - * case2: currentReadAheadCount > readAheadCacheBatchSize - * currentReadAheadBytes < maxReadAheadBytesSize - * result: false - */ - currentReadAheadCount = readAheadCacheBatchSize + 1; - currentReadAheadBytes = 1; - assertFalse(sdb.chargeReadAheadCache(currentReadAheadCount, currentReadAheadBytes)); - - /** - * case3: currentReadAheadCount < readAheadCacheBatchSize - * currentReadAheadBytes > maxReadAheadBytesSize - * result: false - */ - currentReadAheadCount = 1; - currentReadAheadBytes = readAheadCacheMaxSizeMb / 2 * 1024 * 1024 + 1; - assertFalse(sdb.chargeReadAheadCache(currentReadAheadCount, currentReadAheadBytes)); - } catch (Throwable e) { - LOGGER.error("readAheadCacheBatchSizeUnitTest run error", e); - } finally { - teardown(testDB.getStorage(), testDB.getTmpDir()); - } - } - - @Test - public void chargeReadAheadCacheUnitTest() { - TestDB testDB = new TestDB(); - try { - long readAheadCacheMaxSizeMb = 16L; - int readAheadCacheBatchSize = 1024; - long readAheadCacheBatchBytesSize = 2 * 1024 * 1024; - setup(testDB, readAheadCacheMaxSizeMb, readAheadCacheBatchSize, readAheadCacheBatchBytesSize); - SingleDirectoryDbLedgerStorage sdb = testDB.getStorage().getLedgerStorageList().get(0); - /** - * case1: currentReadAheadCount < readAheadCacheBatchSize - * currentReadAheadBytes < readAheadCacheBatchBytesSize - * currentReadAheadBytes < readCacheMaxSize - * result: true - */ - int currentReadAheadCount = 1; - long currentReadAheadBytes = 1; - assertTrue(sdb.chargeReadAheadCache(currentReadAheadCount, currentReadAheadBytes)); - - /** - * case2: currentReadAheadCount > readAheadCacheBatchSize - * currentReadAheadBytes < readAheadCacheBatchBytesSize - * currentReadAheadBytes < readCacheMaxSize - * result: false - */ - currentReadAheadCount = readAheadCacheBatchSize + 1; - currentReadAheadBytes = 1; - assertFalse(sdb.chargeReadAheadCache(currentReadAheadCount, currentReadAheadBytes)); - - /** - * case3: currentReadAheadCount < readAheadCacheBatchSize - * currentReadAheadBytes > readAheadCacheBatchBytesSize - * currentReadAheadBytes < readCacheMaxSize - * result: false - */ - currentReadAheadCount = 1; - currentReadAheadBytes = readAheadCacheBatchBytesSize + 1; - assertFalse(sdb.chargeReadAheadCache(currentReadAheadCount, currentReadAheadBytes)); - } catch (Throwable e) { - LOGGER.error("readAheadCacheBatchSizeUnitTest run error", e); - } finally { - teardown(testDB.getStorage(), testDB.getTmpDir()); - } - } - - @Test - public void compareDiffReadAheadPerfTest() { - /** - * case1(read ahead cache by limit bytes size): - * config: readAheadCacheMaxSizeMb = 2 * 8; - * readAheadCacheBatchSize = 1024; - * readAheadCacheBatchBytesSize = 2 * 1024 * 1024; - * case content: - * LedgerId:0, read 1024 pieces of entry,each piece of entry is 10KB - * LedgerId:1, read 1024 pieces of entry,each piece of entry is 10KB - * LedgerId:2, read 1024 pieces of entry,each piece of entry is 10KB - * LedgerId:3, read 1024 pieces of entry,each piece of entry is 10KB - */ - CacheResult cacheBatchBytesSizeResult = readAheadCacheBatchBytesSize(); - - /** - * case2(read ahead cache by limit count): - * config: readAheadCacheMaxSizeMb = 2 * 8; - * readAheadCacheBatchSize = 1024; - * case content: - * LedgerId:0, read 1024 pieces of entry,each piece of entry is 10KB - * LedgerId:1, read 1024 pieces of entry,each piece of entry is 10KB - * LedgerId:2, read 1024 pieces of entry,each piece of entry is 10KB - * LedgerId:3, read 1024 pieces of entry,each piece of entry is 10KB - */ - CacheResult cacheBatchSizeResult = readAheadCacheBatchSize(); - - /** - * result: case1(read ahead cache by limit bytes size) get less cachemiss, - * it is suitable for large messages, reduce the pollution of readAhead large messages to readCache - */ - assertEquals(8, cacheBatchBytesSizeResult.getCacheMissCount()); - assertEquals(132, cacheBatchSizeResult.getCacheMissCount()); - assertTrue(cacheBatchBytesSizeResult.getCacheMissCount() < cacheBatchSizeResult.getCacheMissCount()); - assertEquals( - cacheBatchBytesSizeResult.getCacheMissCount() + cacheBatchBytesSizeResult.getCacheHitCount(), - cacheBatchSizeResult.getCacheMissCount() + cacheBatchSizeResult.getCacheHitCount()); - } - - public void setup(TestDB testDB, long readAheadCacheMaxSizeMb, - int readAheadCacheBatchSize, long readAheadCacheBatchBytesSize) throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - int gcWaitTime = 1000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - conf.setLedgerDirNames(new String[]{tmpDir.toString()}); - if (readAheadCacheMaxSizeMb > 0) { - conf.setProperty(READ_AHEAD_CACHE_MAX_SIZE_MB, readAheadCacheMaxSizeMb); - } - if (readAheadCacheBatchSize > 0) { - conf.setProperty(READ_AHEAD_CACHE_BATCH_SIZE, readAheadCacheBatchSize); - } - if (readAheadCacheBatchBytesSize > 0) { - conf.setProperty(READ_AHEAD_CACHE_BATCH_BYTES_SIZE, readAheadCacheBatchBytesSize); - } - TestStatsProvider.TestStatsLogger statsLogger = new TestStatsProvider().getStatsLogger("test"); - BookieImpl bookie = new TestBookieImpl(new TestBookieImpl.ResourceBuilder(conf).build(statsLogger), - statsLogger); - - DbLedgerStorage storage = (DbLedgerStorage) bookie.getLedgerStorage(); - - storage.getLedgerStorageList().forEach(singleDirectoryDbLedgerStorage -> { - assertTrue(singleDirectoryDbLedgerStorage.getEntryLogger() instanceof DefaultEntryLogger); - }); - testDB.setStorage(storage); - testDB.setTmpDir(tmpDir); - } - - public void teardown(DbLedgerStorage storage, File tmpDir) { - if (storage != null) { - try { - storage.shutdown(); - } catch (InterruptedException e) { - LOGGER.error("storage.shutdown has error", e); - } - } - if (tmpDir != null) { - tmpDir.delete(); - } - } - - private void addEntries(DbLedgerStorage storage, long minLedgerId, long maxLedgerId, - long minEntryId, long maxEntryId) throws Exception { - // Add entries - for (long lid = minLedgerId; lid < maxLedgerId; lid++) { - long lac = 0; - for (long eid = minEntryId; eid < maxEntryId; eid++) { - ByteBuf entry = Unpooled.buffer(1024); - entry.writeLong(lid); // ledger id - entry.writeLong(eid); // entry id - entry.writeLong(lac); // lac - entry.writeBytes((get4KbMsg()).getBytes()); - assertEquals(eid, storage.addEntry(entry)); - lac++; - } - } - } - - private String get4KbMsg() { - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 1024; i++) { - buffer.append("1234"); - } - assertEquals(4 * 1024, buffer.toString().length()); - return buffer.toString(); - } - - private CacheResult readAheadCacheBatchBytesSize() { - Long cacheMissCount; - TestDB testDB = new TestDB(); - try { - long readAheadCacheMaxSizeMb = 2 * 8L; - int readAheadCacheBatchSize = 1024; - long readAheadCacheBatchBytesSize = 2 * 1024 * 1024; - long minEntryId = 0; - long maxEntryId = 1024; - - setup(testDB, readAheadCacheMaxSizeMb, readAheadCacheBatchSize, readAheadCacheBatchBytesSize); - addEntries(testDB.getStorage(), 0, 4, minEntryId, maxEntryId); - - testDB.getStorage().flush(); - assertEquals(false, testDB.getStorage().isFlushRequired()); - // Read from db - for (long eid = minEntryId; eid < maxEntryId / 2; eid++) { - testDB.getStorage().getEntry(0, eid); - testDB.getStorage().getEntry(1, eid); - testDB.getStorage().getEntry(2, eid); - testDB.getStorage().getEntry(3, eid); - } - List ledgerStorageList = testDB.getStorage().getLedgerStorageList(); - DbLedgerStorageStats ledgerStats = ledgerStorageList.get(0).getDbLedgerStorageStats(); - cacheMissCount = ledgerStats.getReadCacheMissCounter().get(); - Long cacheHitCount = ledgerStats.getReadCacheHitCounter().get(); - LOGGER.info("simple1.cacheMissCount={},cacheHitCount={}", cacheMissCount, cacheHitCount); - return new CacheResult(cacheMissCount, cacheHitCount); - } catch (Throwable e) { - LOGGER.error("test case run error", e); - return new CacheResult(0, 0); - } finally { - teardown(testDB.getStorage(), testDB.getTmpDir()); - } - } - - public CacheResult readAheadCacheBatchSize() { - Long cacheMissCount; - TestDB testDB = new TestDB(); - try { - long readAheadCacheMaxSizeMb = 2 * 8L; - int readAheadCacheBatchSize = 1024; - long readAheadCacheBatchBytesSize = -1; - long minEntryId = 0; - long maxEntryId = 1024; - - setup(testDB, readAheadCacheMaxSizeMb, readAheadCacheBatchSize, readAheadCacheBatchBytesSize); - addEntries(testDB.getStorage(), 0, 4, minEntryId, maxEntryId); - - testDB.getStorage().flush(); - assertEquals(false, testDB.getStorage().isFlushRequired()); - // Read from db - for (long eid = minEntryId; eid < maxEntryId / 2; eid++) { - testDB.getStorage().getEntry(0, eid); - testDB.getStorage().getEntry(1, eid); - testDB.getStorage().getEntry(2, eid); - testDB.getStorage().getEntry(3, eid); - } - List ledgerStorageList = testDB.getStorage().getLedgerStorageList(); - DbLedgerStorageStats ledgerStats = ledgerStorageList.get(0).getDbLedgerStorageStats(); - cacheMissCount = ledgerStats.getReadCacheMissCounter().get(); - Long cacheHitCount = ledgerStats.getReadCacheHitCounter().get(); - LOGGER.info("simple2.cacheMissCount={},cacheHitCount={}", cacheMissCount, cacheHitCount); - return new CacheResult(cacheMissCount, cacheHitCount); - } catch (Throwable e) { - LOGGER.error("test case run error", e); - return new CacheResult(0, 0); - } finally { - teardown(testDB.getStorage(), testDB.getTmpDir()); - } - } - - private class TestDB { - private DbLedgerStorage storage; - private File tmpDir; - - public DbLedgerStorage getStorage() { - return storage; - } - - public void setStorage(DbLedgerStorage storage) { - this.storage = storage; - } - - public File getTmpDir() { - return tmpDir; - } - - public void setTmpDir(File tmpDir) { - this.tmpDir = tmpDir; - } - } - - private class CacheResult { - private long cacheMissCount; - private long cacheHitCount; - - private CacheResult(long cacheMissCount, long cacheHitCount) { - this.cacheMissCount = cacheMissCount; - this.cacheHitCount = cacheHitCount; - } - - public long getCacheMissCount() { - return cacheMissCount; - } - - public void setCacheMissCount(long cacheMissCount) { - this.cacheMissCount = cacheMissCount; - } - - public long getCacheHitCount() { - return cacheHitCount; - } - - public void setCacheHitCount(long cacheHitCount) { - this.cacheHitCount = cacheHitCount; - } - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageTest.java deleted file mode 100644 index 65f11e5d6a3..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageTest.java +++ /dev/null @@ -1,825 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCountUtil; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.List; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.Bookie.NoEntryException; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSourceList; -import org.apache.bookkeeper.bookie.DefaultEntryLogger; -import org.apache.bookkeeper.bookie.EntryLocation; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.LogMark; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.bookie.storage.EntryLogger; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit test for {@link DbLedgerStorage}. - */ -public class DbLedgerStorageTest { - private static final Logger log = LoggerFactory.getLogger(DbLedgerStorageTest.class); - protected DbLedgerStorage storage; - protected File tmpDir; - protected LedgerDirsManager ledgerDirsManager; - protected ServerConfiguration conf; - - @Before - public void setup() throws Exception { - tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - int gcWaitTime = 1000; - conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - BookieImpl bookie = new TestBookieImpl(conf); - - ledgerDirsManager = bookie.getLedgerDirsManager(); - storage = (DbLedgerStorage) bookie.getLedgerStorage(); - - storage.getLedgerStorageList().forEach(singleDirectoryDbLedgerStorage -> { - assertTrue(singleDirectoryDbLedgerStorage.getEntryLogger() instanceof DefaultEntryLogger); - }); - } - - @After - public void teardown() throws Exception { - storage.shutdown(); - tmpDir.delete(); - } - - @Test - public void simple() throws Exception { - assertEquals(false, storage.ledgerExists(3)); - try { - storage.isFenced(3); - fail("should have failed"); - } catch (Bookie.NoLedgerException nle) { - // OK - } - assertEquals(false, storage.ledgerExists(3)); - try { - storage.setFenced(3); - fail("should have failed"); - } catch (Bookie.NoLedgerException nle) { - // OK - } - storage.setMasterKey(3, "key".getBytes()); - try { - storage.setMasterKey(3, "other-key".getBytes()); - fail("should have failed"); - } catch (IOException ioe) { - assertTrue(ioe.getCause() instanceof BookieException.BookieIllegalOpException); - } - // setting the same key is NOOP - storage.setMasterKey(3, "key".getBytes()); - assertEquals(true, storage.ledgerExists(3)); - assertEquals(true, storage.setFenced(3)); - assertEquals(true, storage.isFenced(3)); - assertEquals(false, storage.setFenced(3)); - - storage.setMasterKey(4, "key".getBytes()); - assertEquals(false, storage.isFenced(4)); - assertEquals(true, storage.ledgerExists(4)); - - assertEquals("key", new String(storage.readMasterKey(4))); - - assertEquals(Lists.newArrayList(4L, 3L), Lists.newArrayList(storage.getActiveLedgersInRange(0, 100))); - assertEquals(Lists.newArrayList(4L, 3L), Lists.newArrayList(storage.getActiveLedgersInRange(3, 100))); - assertEquals(Lists.newArrayList(3L), Lists.newArrayList(storage.getActiveLedgersInRange(0, 4))); - - // Add / read entries - ByteBuf entry = Unpooled.buffer(1024); - entry.writeLong(4); // ledger id - entry.writeLong(1); // entry id - entry.writeLong(0); // lac - entry.writeBytes("entry-1".getBytes()); - - assertEquals(false, ((DbLedgerStorage) storage).isFlushRequired()); - - assertEquals(1, storage.addEntry(entry)); - - assertEquals(true, ((DbLedgerStorage) storage).isFlushRequired()); - - // Read from write cache - assertTrue(storage.entryExists(4, 1)); - ByteBuf res = storage.getEntry(4, 1); - assertEquals(entry, res); - - storage.flush(); - - assertEquals(false, ((DbLedgerStorage) storage).isFlushRequired()); - - // Read from db - assertTrue(storage.entryExists(4, 1)); - res = storage.getEntry(4, 1); - assertEquals(entry, res); - - try { - storage.getEntry(4, 2); - fail("Should have thrown exception"); - } catch (NoEntryException e) { - // ok - } - - ByteBuf entry2 = Unpooled.buffer(1024); - entry2.writeLong(4); // ledger id - entry2.writeLong(2); // entry id - entry2.writeLong(1); // lac - entry2.writeBytes("entry-2".getBytes()); - - storage.addEntry(entry2); - - // Read last entry in ledger - res = storage.getEntry(4, BookieProtocol.LAST_ADD_CONFIRMED); - assertEquals(entry2, res); - - // Read last add confirmed in ledger - assertEquals(1L, storage.getLastAddConfirmed(4)); - - ByteBuf entry3 = Unpooled.buffer(1024); - entry3.writeLong(4); // ledger id - entry3.writeLong(3); // entry id - entry3.writeLong(2); // lac - entry3.writeBytes("entry-3".getBytes()); - storage.addEntry(entry3); - - ByteBuf entry4 = Unpooled.buffer(1024); - entry4.writeLong(4); // ledger id - entry4.writeLong(4); // entry id - entry4.writeLong(3); // lac - entry4.writeBytes("entry-4".getBytes()); - storage.addEntry(entry4); - - res = storage.getEntry(4, 4); - assertEquals(entry4, res); - - assertEquals(3, storage.getLastAddConfirmed(4)); - - // Delete - assertEquals(true, storage.ledgerExists(4)); - storage.deleteLedger(4); - assertEquals(false, storage.ledgerExists(4)); - - // remove entries for ledger 4 from cache - storage.flush(); - - try { - storage.getEntry(4, 4); - fail("Should have thrown exception since the ledger was deleted"); - } catch (Bookie.NoLedgerException e) { - // ok - } - } - - @Test - public void testBookieCompaction() throws Exception { - storage.setMasterKey(4, "key".getBytes()); - - ByteBuf entry3 = Unpooled.buffer(1024); - entry3.writeLong(4); // ledger id - entry3.writeLong(3); // entry id - entry3.writeBytes("entry-3".getBytes()); - storage.addEntry(entry3); - - - // Simulate bookie compaction - SingleDirectoryDbLedgerStorage singleDirStorage = ((DbLedgerStorage) storage).getLedgerStorageList().get(0); - EntryLogger entryLogger = singleDirStorage.getEntryLogger(); - // Rewrite entry-3 - ByteBuf newEntry3 = Unpooled.buffer(1024); - newEntry3.writeLong(4); // ledger id - newEntry3.writeLong(3); // entry id - newEntry3.writeBytes("new-entry-3".getBytes()); - long location = entryLogger.addEntry(4L, newEntry3); - newEntry3.resetReaderIndex(); - - storage.flush(); - List locations = Lists.newArrayList(new EntryLocation(4, 3, location)); - singleDirStorage.updateEntriesLocations(locations); - - ByteBuf res = storage.getEntry(4, 3); - System.out.println("res: " + ByteBufUtil.hexDump(res)); - System.out.println("newEntry3: " + ByteBufUtil.hexDump(newEntry3)); - assertEquals(newEntry3, res); - } - - @Test - public void doubleDirectory() throws Exception { - int gcWaitTime = 1000; - File firstDir = new File(tmpDir, "dir1"); - File secondDir = new File(tmpDir, "dir2"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setProperty(DbLedgerStorage.WRITE_CACHE_MAX_SIZE_MB, 4); - conf.setProperty(DbLedgerStorage.READ_AHEAD_CACHE_MAX_SIZE_MB, 4); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - conf.setLedgerDirNames(new String[] { firstDir.getCanonicalPath(), secondDir.getCanonicalPath() }); - - // Should not fail - Bookie bookie = new TestBookieImpl(conf); - assertEquals(2, ((DbLedgerStorage) bookie.getLedgerStorage()).getLedgerStorageList().size()); - - bookie.shutdown(); - } - - @Test - public void testRewritingEntries() throws Exception { - storage.setMasterKey(1, "key".getBytes()); - - try { - storage.getEntry(1, -1); - fail("Should throw exception"); - } catch (Bookie.NoEntryException e) { - // ok - } - - ByteBuf entry1 = Unpooled.buffer(1024); - entry1.writeLong(1); // ledger id - entry1.writeLong(1); // entry id - entry1.writeBytes("entry-1".getBytes()); - - storage.addEntry(entry1); - storage.flush(); - - ByteBuf newEntry1 = Unpooled.buffer(1024); - newEntry1.writeLong(1); // ledger id - newEntry1.writeLong(1); // entry id - newEntry1.writeBytes("new-entry-1".getBytes()); - - storage.addEntry(newEntry1); - storage.flush(); - - ByteBuf response = storage.getEntry(1, 1); - assertEquals(newEntry1, response); - } - - @Test - public void testEntriesOutOfOrder() throws Exception { - storage.setMasterKey(1, "key".getBytes()); - - ByteBuf entry2 = Unpooled.buffer(1024); - entry2.writeLong(1); // ledger id - entry2.writeLong(2); // entry id - entry2.writeBytes("entry-2".getBytes()); - - storage.addEntry(entry2); - - try { - storage.getEntry(1, 1); - fail("Entry doesn't exist"); - } catch (NoEntryException e) { - // Ok, entry doesn't exist - } - - ByteBuf res = storage.getEntry(1, 2); - assertEquals(entry2, res); - - ByteBuf entry1 = Unpooled.buffer(1024); - entry1.writeLong(1); // ledger id - entry1.writeLong(1); // entry id - entry1.writeBytes("entry-1".getBytes()); - - storage.addEntry(entry1); - - res = storage.getEntry(1, 1); - assertEquals(entry1, res); - - res = storage.getEntry(1, 2); - assertEquals(entry2, res); - - storage.flush(); - - res = storage.getEntry(1, 1); - assertEquals(entry1, res); - - res = storage.getEntry(1, 2); - assertEquals(entry2, res); - } - - @Test - public void testEntriesOutOfOrderWithFlush() throws Exception { - storage.setMasterKey(1, "key".getBytes()); - - ByteBuf entry2 = Unpooled.buffer(1024); - entry2.writeLong(1); // ledger id - entry2.writeLong(2); // entry id - entry2.writeBytes("entry-2".getBytes()); - - storage.addEntry(entry2); - - try { - storage.getEntry(1, 1); - fail("Entry doesn't exist"); - } catch (NoEntryException e) { - // Ok, entry doesn't exist - } - - ByteBuf res = storage.getEntry(1, 2); - assertEquals(entry2, res); - ReferenceCountUtil.release(res); - - storage.flush(); - - try { - storage.getEntry(1, 1); - fail("Entry doesn't exist"); - } catch (NoEntryException e) { - // Ok, entry doesn't exist - } - - res = storage.getEntry(1, 2); - assertEquals(entry2, res); - ReferenceCountUtil.release(res); - - ByteBuf entry1 = Unpooled.buffer(1024); - entry1.writeLong(1); // ledger id - entry1.writeLong(1); // entry id - entry1.writeBytes("entry-1".getBytes()); - - storage.addEntry(entry1); - - res = storage.getEntry(1, 1); - assertEquals(entry1, res); - ReferenceCountUtil.release(res); - - res = storage.getEntry(1, 2); - assertEquals(entry2, res); - ReferenceCountUtil.release(res); - - storage.flush(); - - res = storage.getEntry(1, 1); - assertEquals(entry1, res); - ReferenceCountUtil.release(res); - - res = storage.getEntry(1, 2); - assertEquals(entry2, res); - ReferenceCountUtil.release(res); - } - - @Test - public void testAddEntriesAfterDelete() throws Exception { - storage.setMasterKey(1, "key".getBytes()); - - ByteBuf entry0 = Unpooled.buffer(1024); - entry0.writeLong(1); // ledger id - entry0.writeLong(0); // entry id - entry0.writeBytes("entry-0".getBytes()); - - ByteBuf entry1 = Unpooled.buffer(1024); - entry1.writeLong(1); // ledger id - entry1.writeLong(1); // entry id - entry1.writeBytes("entry-1".getBytes()); - - storage.addEntry(entry0); - storage.addEntry(entry1); - - storage.flush(); - - storage.deleteLedger(1); - - storage.setMasterKey(1, "key".getBytes()); - - entry0 = Unpooled.buffer(1024); - entry0.writeLong(1); // ledger id - entry0.writeLong(0); // entry id - entry0.writeBytes("entry-0".getBytes()); - - entry1 = Unpooled.buffer(1024); - entry1.writeLong(1); // ledger id - entry1.writeLong(1); // entry id - entry1.writeBytes("entry-1".getBytes()); - - storage.addEntry(entry0); - storage.addEntry(entry1); - - assertEquals(entry0, storage.getEntry(1, 0)); - assertEquals(entry1, storage.getEntry(1, 1)); - - storage.flush(); - } - - @Test - public void testLimboStateSucceedsWhenInLimboButHasEntry() throws Exception { - storage.setMasterKey(1, "foobar".getBytes()); - - ByteBuf entry0 = Unpooled.buffer(1024); - entry0.writeLong(1); // ledger id - entry0.writeLong(0); // entry id - entry0.writeBytes("entry-0".getBytes()); - - storage.addEntry(entry0); - storage.flush(); - storage.setLimboState(1); - - try { - storage.getEntry(1, 0); - } catch (BookieException.DataUnknownException e) { - fail("Should have been able to read entry"); - } - } - - @Test - public void testLimboStateThrowsInLimboWhenNoEntry() throws Exception { - storage.setMasterKey(1, "foobar".getBytes()); - - ByteBuf entry0 = Unpooled.buffer(1024); - entry0.writeLong(1); // ledger id - entry0.writeLong(1); // entry id - entry0.writeBytes("entry-0".getBytes()); - - storage.addEntry(entry0); - storage.flush(); - storage.setLimboState(1); - - try { - storage.getEntry(1, 1); - } catch (NoEntryException nee) { - fail("Shouldn't have seen NoEntryException"); - } catch (BookieException.DataUnknownException e) { - // expected - } - - storage.shutdown(); - Bookie restartedBookie = new TestBookieImpl(conf); - DbLedgerStorage restartedStorage = (DbLedgerStorage) restartedBookie.getLedgerStorage(); - try { - try { - restartedStorage.getEntry(1, 1); - } catch (NoEntryException nee) { - fail("Shouldn't have seen NoEntryException"); - } catch (BookieException.DataUnknownException e) { - // expected - } - } finally { - restartedStorage.shutdown(); - } - - storage = (DbLedgerStorage) new TestBookieImpl(conf).getLedgerStorage(); - } - - @Test - public void testLimboStateThrowsNoEntryExceptionWhenLimboCleared() throws Exception { - storage.setMasterKey(1, "foobar".getBytes()); - - ByteBuf entry0 = Unpooled.buffer(1024); - entry0.writeLong(1); // ledger id - entry0.writeLong(1); // entry id - entry0.writeBytes("entry-0".getBytes()); - - storage.addEntry(entry0); - storage.flush(); - storage.setLimboState(1); - - try { - storage.getEntry(1, 1); - } catch (NoEntryException nee) { - fail("Shouldn't have seen NoEntryException"); - } catch (BookieException.DataUnknownException e) { - // expected - } - - storage.clearLimboState(1); - try { - storage.getEntry(1, 1); - } catch (NoEntryException nee) { - // expected - } catch (BookieException.DataUnknownException e) { - fail("Should have seen NoEntryException"); - } - } - - @Test - public void testLimboStateSucceedsWhenFenced() throws Exception { - storage.setMasterKey(1, "foobar".getBytes()); - - ByteBuf entry0 = Unpooled.buffer(1024); - entry0.writeLong(1); // ledger id - entry0.writeLong(1); // entry id - entry0.writeBytes("entry-0".getBytes()); - - storage.addEntry(entry0); - storage.flush(); - storage.setFenced(1); - storage.setLimboState(1); - - try { - storage.isFenced(1); - } catch (IOException ioe) { - fail("Should have been able to get isFenced response"); - } - } - - @Test - public void testLimboStateThrowsInLimboWhenNotFenced() throws Exception { - storage.setMasterKey(1, "foobar".getBytes()); - - ByteBuf entry0 = Unpooled.buffer(1024); - entry0.writeLong(1); // ledger id - entry0.writeLong(1); // entry id - entry0.writeBytes("entry-0".getBytes()); - - storage.addEntry(entry0); - storage.flush(); - storage.setLimboState(1); - - try { - storage.isFenced(1); - fail("Shouldn't have been able to get isFenced response"); - } catch (BookieException.DataUnknownException e) { - // expected - } - } - - @Test - public void testHasEntry() throws Exception { - long ledgerId = 0xbeefee; - storage.setMasterKey(ledgerId, "foobar".getBytes()); - - ByteBuf entry0 = Unpooled.buffer(1024); - entry0.writeLong(ledgerId); // ledger id - entry0.writeLong(0); // entry id - entry0.writeBytes("entry-0".getBytes()); - - storage.addEntry(entry0); - - // should come from write cache - assertTrue(storage.entryExists(ledgerId, 0)); - assertFalse(storage.entryExists(ledgerId, 1)); - - storage.flush(); - - // should come from storage - assertTrue(storage.entryExists(ledgerId, 0)); - assertFalse(storage.entryExists(ledgerId, 1)); - - // pull entry into readcache - storage.getEntry(ledgerId, 0); - - // should come from read cache - assertTrue(storage.entryExists(ledgerId, 0)); - assertFalse(storage.entryExists(ledgerId, 1)); - } - - @Test - public void testStorageStateFlags() throws Exception { - assertTrue(storage.getStorageStateFlags().isEmpty()); - - storage.setStorageStateFlag(LedgerStorage.StorageState.NEEDS_INTEGRITY_CHECK); - assertTrue(storage.getStorageStateFlags() - .contains(LedgerStorage.StorageState.NEEDS_INTEGRITY_CHECK)); - - storage.shutdown(); - Bookie restartedBookie1 = new TestBookieImpl(conf); - DbLedgerStorage restartedStorage1 = (DbLedgerStorage) restartedBookie1.getLedgerStorage(); - try { - assertTrue(restartedStorage1.getStorageStateFlags() - .contains(LedgerStorage.StorageState.NEEDS_INTEGRITY_CHECK)); - restartedStorage1.clearStorageStateFlag(LedgerStorage.StorageState.NEEDS_INTEGRITY_CHECK); - - assertFalse(restartedStorage1.getStorageStateFlags() - .contains(LedgerStorage.StorageState.NEEDS_INTEGRITY_CHECK)); - - } finally { - restartedStorage1.shutdown(); - } - - Bookie restartedBookie2 = new TestBookieImpl(conf); - DbLedgerStorage restartedStorage2 = (DbLedgerStorage) restartedBookie2.getLedgerStorage(); - try { - assertFalse(restartedStorage2.getStorageStateFlags() - .contains(LedgerStorage.StorageState.NEEDS_INTEGRITY_CHECK)); - } finally { - restartedStorage2.shutdown(); - } - - storage = (DbLedgerStorage) new TestBookieImpl(conf).getLedgerStorage(); - } - - @Test - public void testMultiLedgerDirectoryCheckpoint() throws Exception { - int gcWaitTime = 1000; - File firstDir = new File(tmpDir, "dir1"); - File secondDir = new File(tmpDir, "dir2"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setProperty(DbLedgerStorage.WRITE_CACHE_MAX_SIZE_MB, 4); - conf.setProperty(DbLedgerStorage.READ_AHEAD_CACHE_MAX_SIZE_MB, 4); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - conf.setLedgerDirNames(new String[] { firstDir.getCanonicalPath(), secondDir.getCanonicalPath() }); - - BookieImpl bookie = new TestBookieImpl(conf); - ByteBuf entry1 = Unpooled.buffer(1024); - entry1.writeLong(1); // ledger id - entry1.writeLong(2); // entry id - entry1.writeBytes("entry-1".getBytes()); - - bookie.getLedgerStorage().addEntry(entry1); - // write one entry to first ledger directory and flush with logMark(1, 2), - // only the first ledger directory should have lastMark - bookie.getJournals().get(0).getLastLogMark().getCurMark().setLogMark(1, 2); - ((DbLedgerStorage) bookie.getLedgerStorage()).getLedgerStorageList().get(0).flush(); - - File firstDirMark = new File(firstDir + "/current", "lastMark"); - File secondDirMark = new File(secondDir + "/current", "lastMark"); - - // LedgerStorage flush won't trigger lastMark update due to two ledger directories configured - try { - readLogMark(firstDirMark); - readLogMark(secondDirMark); - fail(); - } catch (Exception e) { - // - } - - // write the second entry to second leger directory and flush with log(4, 5), - // the fist ledger directory's lastMark is (1, 2) and the second ledger directory's lastMark is (4, 5); - ByteBuf entry2 = Unpooled.buffer(1024); - entry2.writeLong(2); // ledger id - entry2.writeLong(1); // entry id - entry2.writeBytes("entry-2".getBytes()); - - bookie.getLedgerStorage().addEntry(entry2); - // write one entry to first ledger directory and flush with logMark(1, 2), - // only the first ledger directory should have lastMark - bookie.getJournals().get(0).getLastLogMark().getCurMark().setLogMark(4, 5); - ((DbLedgerStorage) bookie.getLedgerStorage()).getLedgerStorageList().get(1).flush(); - - // LedgerStorage flush won't trigger lastMark update due to two ledger directories configured - try { - readLogMark(firstDirMark); - readLogMark(secondDirMark); - fail(); - } catch (Exception e) { - // - } - - // The dbLedgerStorage flush also won't trigger lastMark update due to two ledger directories configured. - bookie.getLedgerStorage().flush(); - try { - readLogMark(firstDirMark); - readLogMark(secondDirMark); - fail(); - } catch (Exception e) { - // - } - - // trigger checkpoint simulate SyncThread do checkpoint. - CheckpointSource checkpointSource = new CheckpointSourceList(bookie.getJournals()); - bookie.getJournals().get(0).getLastLogMark().getCurMark().setLogMark(7, 8); - CheckpointSource.Checkpoint checkpoint = checkpointSource.newCheckpoint(); - checkpointSource.checkpointComplete(checkpoint, false); - - try { - LogMark firstLogMark = readLogMark(firstDirMark); - LogMark secondLogMark = readLogMark(secondDirMark); - assertEquals(7, firstLogMark.getLogFileId()); - assertEquals(8, firstLogMark.getLogFileOffset()); - assertEquals(7, secondLogMark.getLogFileId()); - assertEquals(8, secondLogMark.getLogFileOffset()); - } catch (Exception e) { - fail(); - } - - // test replay journal lastMark, to make sure we get the right LastMark position - bookie.getJournals().get(0).getLastLogMark().readLog(); - LogMark logMark = bookie.getJournals().get(0).getLastLogMark().getCurMark(); - assertEquals(7, logMark.getLogFileId()); - assertEquals(8, logMark.getLogFileOffset()); - } - - private LogMark readLogMark(File file) throws IOException { - byte[] buff = new byte[16]; - ByteBuffer bb = ByteBuffer.wrap(buff); - LogMark mark = new LogMark(); - try (FileInputStream fis = new FileInputStream(file)) { - int bytesRead = fis.read(buff); - if (bytesRead != 16) { - throw new IOException("Couldn't read enough bytes from lastMark." - + " Wanted " + 16 + ", got " + bytesRead); - } - } - bb.clear(); - mark.readLogMark(bb); - - return mark; - } - - @Test - public void testSingleLedgerDirectoryCheckpoint() throws Exception { - int gcWaitTime = 1000; - File ledgerDir = new File(tmpDir, "dir"); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setProperty(DbLedgerStorage.WRITE_CACHE_MAX_SIZE_MB, 4); - conf.setProperty(DbLedgerStorage.READ_AHEAD_CACHE_MAX_SIZE_MB, 4); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - conf.setLedgerDirNames(new String[] { ledgerDir.getCanonicalPath() }); - - BookieImpl bookie = new TestBookieImpl(conf); - ByteBuf entry1 = Unpooled.buffer(1024); - entry1.writeLong(1); // ledger id - entry1.writeLong(2); // entry id - entry1.writeBytes("entry-1".getBytes()); - bookie.getLedgerStorage().addEntry(entry1); - - bookie.getJournals().get(0).getLastLogMark().getCurMark().setLogMark(1, 2); - ((DbLedgerStorage) bookie.getLedgerStorage()).getLedgerStorageList().get(0).flush(); - - File ledgerDirMark = new File(ledgerDir + "/current", "lastMark"); - try { - LogMark logMark = readLogMark(ledgerDirMark); - assertEquals(1, logMark.getLogFileId()); - assertEquals(2, logMark.getLogFileOffset()); - } catch (Exception e) { - fail(); - } - - ByteBuf entry2 = Unpooled.buffer(1024); - entry2.writeLong(2); // ledger id - entry2.writeLong(1); // entry id - entry2.writeBytes("entry-2".getBytes()); - - bookie.getLedgerStorage().addEntry(entry2); - // write one entry to first ledger directory and flush with logMark(1, 2), - // only the first ledger directory should have lastMark - bookie.getJournals().get(0).getLastLogMark().getCurMark().setLogMark(4, 5); - - bookie.getLedgerStorage().flush(); - try { - LogMark logMark = readLogMark(ledgerDirMark); - assertEquals(4, logMark.getLogFileId()); - assertEquals(5, logMark.getLogFileOffset()); - } catch (Exception e) { - fail(); - } - - CheckpointSource checkpointSource = new CheckpointSourceList(bookie.getJournals()); - bookie.getJournals().get(0).getLastLogMark().getCurMark().setLogMark(7, 8); - CheckpointSource.Checkpoint checkpoint = checkpointSource.newCheckpoint(); - checkpointSource.checkpointComplete(checkpoint, false); - - try { - LogMark firstLogMark = readLogMark(ledgerDirMark); - assertEquals(7, firstLogMark.getLogFileId()); - assertEquals(8, firstLogMark.getLogFileOffset()); - } catch (Exception e) { - fail(); - } - - // test replay journal lastMark, to make sure we get the right LastMark position - bookie.getJournals().get(0).getLastLogMark().readLog(); - LogMark logMark = bookie.getJournals().get(0).getLastLogMark().getCurMark(); - assertEquals(7, logMark.getLogFileId()); - assertEquals(8, logMark.getLogFileOffset()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWithDirectEntryLoggerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWithDirectEntryLoggerTest.java deleted file mode 100644 index 76192cf2b40..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWithDirectEntryLoggerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.bookie.storage.directentrylogger.DirectEntryLogger; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.junit.Before; - -/** - * Unit test for {@link DbLedgerStorage} with directIO entrylogger. - */ -public class DbLedgerStorageWithDirectEntryLoggerTest extends DbLedgerStorageTest { - - @Override - @Before - public void setup() throws Exception { - tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - int gcWaitTime = 1000; - conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - conf.setProperty("dbStorage_directIOEntryLogger", true); - BookieImpl bookie = new TestBookieImpl(conf); - - ledgerDirsManager = bookie.getLedgerDirsManager(); - storage = (DbLedgerStorage) bookie.getLedgerStorage(); - - storage.getLedgerStorageList().forEach(singleDirectoryDbLedgerStorage -> { - assertTrue(singleDirectoryDbLedgerStorage.getEntryLogger() instanceof DirectEntryLogger); - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWriteCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWriteCacheTest.java deleted file mode 100644 index 102f7f5addc..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWriteCacheTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.io.IOException; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException.OperationRejectedException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.bookie.storage.EntryLogger; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.stats.StatsLogger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link DbLedgerStorage}. - */ -public class DbLedgerStorageWriteCacheTest { - - private DbLedgerStorage storage; - private File tmpDir; - - private static class MockedDbLedgerStorage extends DbLedgerStorage { - - @Override - protected SingleDirectoryDbLedgerStorage newSingleDirectoryDbLedgerStorage(ServerConfiguration conf, - LedgerManager ledgerManager, LedgerDirsManager ledgerDirsManager, LedgerDirsManager indexDirsManager, - EntryLogger entryLogger, StatsLogger statsLogger, - long writeCacheSize, long readCacheSize, int readAheadCacheBatchSize, long readAheadCacheBatchBytesSize) - throws IOException { - return new MockedSingleDirectoryDbLedgerStorage(conf, ledgerManager, ledgerDirsManager, indexDirsManager, - entryLogger, statsLogger, allocator, writeCacheSize, - readCacheSize, readAheadCacheBatchSize, readAheadCacheBatchBytesSize); - } - - private static class MockedSingleDirectoryDbLedgerStorage extends SingleDirectoryDbLedgerStorage { - public MockedSingleDirectoryDbLedgerStorage(ServerConfiguration conf, LedgerManager ledgerManager, - LedgerDirsManager ledgerDirsManager, LedgerDirsManager indexDirsManager, EntryLogger entryLogger, - StatsLogger statsLogger, - ByteBufAllocator allocator, long writeCacheSize, - long readCacheSize, int readAheadCacheBatchSize, long readAheadCacheBatchBytesSize) - throws IOException { - super(conf, ledgerManager, ledgerDirsManager, indexDirsManager, entryLogger, - statsLogger, allocator, writeCacheSize, readCacheSize, readAheadCacheBatchSize, - readAheadCacheBatchBytesSize); - } - - @Override - public void flush() throws IOException { - flushMutex.lock(); - try { - // Swap the write caches and block indefinitely to simulate a slow disk - WriteCache tmp = writeCacheBeingFlushed; - writeCacheBeingFlushed = writeCache; - writeCache = tmp; - - // since the cache is switched, we can allow flush to be triggered - hasFlushBeenTriggered.set(false); - - // Block the flushing thread - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - } finally { - flushMutex.unlock(); - } - } - } - } - - @Before - public void setup() throws Exception { - tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - int gcWaitTime = 1000; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(gcWaitTime); - conf.setLedgerStorageClass(MockedDbLedgerStorage.class.getName()); - conf.setProperty(DbLedgerStorage.WRITE_CACHE_MAX_SIZE_MB, 1); - conf.setProperty(DbLedgerStorage.MAX_THROTTLE_TIME_MILLIS, 1000); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - Bookie bookie = new TestBookieImpl(conf); - - storage = (DbLedgerStorage) bookie.getLedgerStorage(); - } - - @After - public void teardown() throws Exception { - storage.shutdown(); - tmpDir.delete(); - } - - @Test - public void writeCacheFull() throws Exception { - storage.setMasterKey(4, "key".getBytes()); - assertEquals(false, storage.isFenced(4)); - assertEquals(true, storage.ledgerExists(4)); - - assertEquals("key", new String(storage.readMasterKey(4))); - - // Add enough entries to fill the 1st write cache - for (int i = 0; i < 5; i++) { - ByteBuf entry = Unpooled.buffer(100 * 1024 + 2 * 8); - entry.writeLong(4); // ledger id - entry.writeLong(i); // entry id - entry.writeZero(100 * 1024); - storage.addEntry(entry); - } - - for (int i = 0; i < 5; i++) { - ByteBuf entry = Unpooled.buffer(100 * 1024 + 2 * 8); - entry.writeLong(4); // ledger id - entry.writeLong(5 + i); // entry id - entry.writeZero(100 * 1024); - storage.addEntry(entry); - } - - // Next add should fail for cache full - ByteBuf entry = Unpooled.buffer(100 * 1024 + 2 * 8); - entry.writeLong(4); // ledger id - entry.writeLong(22); // entry id - entry.writeZero(100 * 1024); - - try { - storage.addEntry(entry); - fail("Should have thrown exception"); - } catch (OperationRejectedException e) { - // Expected - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbReadLedgerIndexEntriesTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbReadLedgerIndexEntriesTest.java deleted file mode 100644 index c4ee2a8326f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbReadLedgerIndexEntriesTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for class {@link DbLedgerStorage#readLedgerIndexEntries}. - */ -public class DbReadLedgerIndexEntriesTest { - private static final int TEST_LEDGER_MIN_ID = 0; - private static final int TEST_LEDGER_MAX_ID = 5; - private static final int TEST_ENTRY_MIN_ID = 0; - private static final int TEST_ENTRY_MAX_ID = 10; - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - protected final TmpDirs tmpDirs = new TmpDirs(); - - private String newDirectory() throws Exception { - File d = tmpDirs.createNew("bkTest", ".dir"); - d.delete(); - d.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(d); - BookieImpl.checkDirectoryStructure(curDir); - return d.getPath(); - } - - @Test - public void testReadLedgerIndexEntries() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[]{newDirectory(), newDirectory()}); - conf.setIndexDirName(new String[]{newDirectory(), newDirectory()}); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), diskChecker); - LedgerDirsManager indexDirsManager = new LedgerDirsManager(conf, conf.getIndexDirs(), diskChecker); - - DbLedgerStorage ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, indexDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - ledgerStorage.setCheckpointer(checkpointer); - ledgerStorage.setCheckpointSource(checkpointSource); - - // Insert some ledger & entries in the storage - for (long ledgerId = TEST_LEDGER_MIN_ID; ledgerId <= TEST_LEDGER_MAX_ID; ledgerId++) { - ledgerStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - ledgerStorage.setFenced(ledgerId); - - for (long entryId = TEST_ENTRY_MIN_ID; entryId <= TEST_ENTRY_MAX_ID; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ledgerStorage.addEntry(entry); - } - } - - ledgerStorage.flush(); - ledgerStorage.shutdown(); - - // read ledger index entries - long ledgerId = TEST_LEDGER_MIN_ID; - try { - for (ledgerId = TEST_LEDGER_MIN_ID; ledgerId <= TEST_LEDGER_MAX_ID; ledgerId++) { - BlockingQueue entrys = new ArrayBlockingQueue<>(TEST_ENTRY_MAX_ID + 1); - DbLedgerStorage.readLedgerIndexEntries(ledgerId, conf, (eId, entryLodId, pos) -> { - System.out.println("entry " + eId + "\t:\t(log: " + entryLodId + ", pos: " + pos + ")"); - entrys.add(eId); - }); - for (long entryId = TEST_ENTRY_MIN_ID; entryId <= TEST_ENTRY_MAX_ID; entryId++) { - Assert.assertTrue(entrys.contains(entryId)); - } - } - } catch (Exception e) { - System.err.printf("ERROR: initializing dbLedgerStorage %s", e.getMessage()); - Assert.fail("fail to read this ledger(" + ledgerId + ") index entries"); - } - - List toDeleted = Lists.newArrayList(conf.getLedgerDirNames()); - toDeleted.addAll(Lists.newArrayList(conf.getIndexDirNames())); - toDeleted.forEach(d -> { - try { - FileUtils.forceDelete(new File(d)); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/EntryLocationIndexTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/EntryLocationIndexTest.java deleted file mode 100644 index 765065f0b74..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/EntryLocationIndexTest.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Test; - -/** - * Unit test for {@link EntryLocationIndex}. - */ -public class EntryLocationIndexTest { - - private final ServerConfiguration serverConfiguration = new ServerConfiguration(); - - @Test - public void deleteLedgerTest() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - tmpDir.deleteOnExit(); - - EntryLocationIndex idx = new EntryLocationIndex(serverConfiguration, KeyValueStorageRocksDB.factory, - tmpDir.getAbsolutePath(), NullStatsLogger.INSTANCE); - - // Add some dummy indexes - idx.addLocation(40312, 0, 1); - idx.addLocation(40313, 10, 2); - idx.addLocation(40320, 0, 3); - - // Add more indexes in a different batch - idx.addLocation(40313, 11, 5); - idx.addLocation(40313, 12, 6); - idx.addLocation(40320, 1, 7); - idx.addLocation(40312, 3, 4); - - idx.delete(40313); - - assertEquals(1, idx.getLocation(40312, 0)); - assertEquals(4, idx.getLocation(40312, 3)); - assertEquals(3, idx.getLocation(40320, 0)); - assertEquals(7, idx.getLocation(40320, 1)); - - assertEquals(2, idx.getLocation(40313, 10)); - assertEquals(5, idx.getLocation(40313, 11)); - assertEquals(6, idx.getLocation(40313, 12)); - - idx.removeOffsetFromDeletedLedgers(); - - // After flush the keys will be removed - assertEquals(0, idx.getLocation(40313, 10)); - assertEquals(0, idx.getLocation(40313, 11)); - assertEquals(0, idx.getLocation(40313, 12)); - - idx.close(); - } - - @Test - public void deleteBatchLedgersTest() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - tmpDir.deleteOnExit(); - - EntryLocationIndex idx = new EntryLocationIndex(serverConfiguration, KeyValueStorageRocksDB.factory, - tmpDir.getAbsolutePath(), NullStatsLogger.INSTANCE); - - int numLedgers = 1000; - int numEntriesPerLedger = 100; - - int location = 0; - KeyValueStorage.Batch batch = idx.newBatch(); - for (int entryId = 0; entryId < numEntriesPerLedger; ++entryId) { - for (int ledgerId = 0; ledgerId < numLedgers; ++ledgerId) { - idx.addLocation(batch, ledgerId, entryId, location); - location++; - } - } - batch.flush(); - batch.close(); - - - int expectedLocation = 0; - for (int entryId = 0; entryId < numEntriesPerLedger; ++entryId) { - for (int ledgerId = 0; ledgerId < numLedgers; ++ledgerId) { - assertEquals(expectedLocation, idx.getLocation(ledgerId, entryId)); - expectedLocation++; - } - } - - for (int ledgerId = 0; ledgerId < numLedgers; ++ledgerId) { - if (ledgerId % 2 == 0) { - idx.delete(ledgerId); - } - } - - expectedLocation = 0; - for (int entryId = 0; entryId < numEntriesPerLedger; ++entryId) { - for (int ledgerId = 0; ledgerId < numLedgers; ++ledgerId) { - assertEquals(expectedLocation, idx.getLocation(ledgerId, entryId)); - expectedLocation++; - } - } - - idx.removeOffsetFromDeletedLedgers(); - - expectedLocation = 0; - for (int entryId = 0; entryId < numEntriesPerLedger; ++entryId) { - for (int ledgerId = 0; ledgerId < numLedgers; ++ledgerId) { - if (ledgerId % 2 == 0) { - assertEquals(0, idx.getLocation(ledgerId, entryId)); - } else { - assertEquals(expectedLocation, idx.getLocation(ledgerId, entryId)); - } - expectedLocation++; - } - } - - idx.close(); - } - - // this tests if a ledger is added after it has been deleted - @Test - public void addLedgerAfterDeleteTest() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - tmpDir.deleteOnExit(); - - EntryLocationIndex idx = new EntryLocationIndex(serverConfiguration, KeyValueStorageRocksDB.factory, - tmpDir.getAbsolutePath(), NullStatsLogger.INSTANCE); - - // Add some dummy indexes - idx.addLocation(40312, 0, 1); - idx.addLocation(40313, 10, 2); - idx.addLocation(40320, 0, 3); - - idx.delete(40313); - - // Add more indexes in a different batch - idx.addLocation(40313, 11, 5); - idx.addLocation(40313, 12, 6); - idx.addLocation(40320, 1, 7); - idx.addLocation(40312, 3, 4); - - idx.removeOffsetFromDeletedLedgers(); - - assertEquals(0, idx.getLocation(40313, 11)); - assertEquals(0, idx.getLocation(40313, 12)); - - idx.close(); - } - - // test non exist entry - @Test - public void testDeleteSpecialEntry() throws IOException { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - tmpDir.deleteOnExit(); - - EntryLocationIndex idx = new EntryLocationIndex(serverConfiguration, KeyValueStorageRocksDB.factory, - tmpDir.getAbsolutePath(), NullStatsLogger.INSTANCE); - - // Add some dummy indexes - idx.addLocation(40312, -1, 1); - idx.addLocation(40313, 10, 2); - idx.addLocation(40320, 0, 3); - - // Add more indexes in a different batch - idx.addLocation(40313, 11, 5); - idx.addLocation(40313, 12, 6); - idx.addLocation(40320, 1, 7); - - // delete a non exist entry - idx.delete(40312); - idx.removeOffsetFromDeletedLedgers(); - - // another delete entry operation shouldn't effected - idx.delete(40313); - idx.removeOffsetFromDeletedLedgers(); - assertEquals(0, idx.getLocation(40312, 10)); - } - - @Test - public void testEntryIndexLookupLatencyStats() throws IOException { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - tmpDir.deleteOnExit(); - - TestStatsProvider statsProvider = new TestStatsProvider(); - EntryLocationIndex idx = new EntryLocationIndex(serverConfiguration, KeyValueStorageRocksDB.factory, - tmpDir.getAbsolutePath(), statsProvider.getStatsLogger("scope")); - - // Add some dummy indexes - idx.addLocation(40313, 11, 5); - - // successful lookup - assertEquals(5, idx.getLocation(40313, 11)); - TestStatsProvider.TestOpStatsLogger lookupEntryLocationOpStats = - statsProvider.getOpStatsLogger("scope.lookup-entry-location"); - assertEquals(1, lookupEntryLocationOpStats.getSuccessCount()); - assertTrue(lookupEntryLocationOpStats.getSuccessAverage() > 0); - - // failed lookup - assertEquals(0, idx.getLocation(12345, 1)); - assertEquals(1, lookupEntryLocationOpStats.getFailureCount()); - assertEquals(1, lookupEntryLocationOpStats.getSuccessCount()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java deleted file mode 100644 index 2ef3e010f8b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.junit.Test; -import org.rocksdb.BlockBasedTableConfig; -import org.rocksdb.ChecksumType; -import org.rocksdb.ColumnFamilyDescriptor; -import org.rocksdb.ColumnFamilyOptions; -import org.rocksdb.CompressionType; -import org.rocksdb.DBOptions; -import org.rocksdb.Options; - -public class KeyValueStorageRocksDBTest { - - @Test - public void testRocksDBInitiateWithBookieConfiguration() throws Exception { - ServerConfiguration configuration = new ServerConfiguration(); - configuration.setEntryLocationRocksdbConf("entry_location_rocksdb.conf"); - File tmpDir = Files.createTempDirectory("bk-kv-rocksdbtest-conf").toFile(); - Files.createDirectory(Paths.get(tmpDir.toString(), "subDir")); - KeyValueStorageRocksDB rocksDB = new KeyValueStorageRocksDB(tmpDir.toString(), "subDir", - KeyValueStorageFactory.DbConfigType.EntryLocation, configuration); - assertNull(rocksDB.getColumnFamilyDescriptors()); - - Options options = (Options) rocksDB.getOptions(); - assertEquals(64 * 1024 * 1024, options.writeBufferSize()); - assertEquals(4, options.maxWriteBufferNumber()); - assertEquals(256 * 1024 * 1024, options.maxBytesForLevelBase()); - assertEquals(true, options.levelCompactionDynamicLevelBytes()); - rocksDB.close(); - } - - @Test - public void testRocksDBInitiateWithConfigurationFile() throws Exception { - ServerConfiguration configuration = new ServerConfiguration(); - URL url = getClass().getClassLoader().getResource("test_entry_location_rocksdb.conf"); - configuration.setEntryLocationRocksdbConf(url.getPath()); - File tmpDir = Files.createTempDirectory("bk-kv-rocksdbtest-file").toFile(); - Files.createDirectory(Paths.get(tmpDir.toString(), "subDir")); - KeyValueStorageRocksDB rocksDB = new KeyValueStorageRocksDB(tmpDir.toString(), "subDir", - KeyValueStorageFactory.DbConfigType.EntryLocation, configuration); - assertNotNull(rocksDB.getColumnFamilyDescriptors()); - - DBOptions dbOptions = (DBOptions) rocksDB.getOptions(); - assertTrue(dbOptions.createIfMissing()); - assertEquals(1, dbOptions.keepLogFileNum()); - assertEquals(1000, dbOptions.maxTotalWalSize()); - - List columnFamilyDescriptorList = rocksDB.getColumnFamilyDescriptors(); - ColumnFamilyOptions familyOptions = columnFamilyDescriptorList.get(0).getOptions(); - assertEquals(CompressionType.LZ4_COMPRESSION, familyOptions.compressionType()); - assertEquals(1024, familyOptions.writeBufferSize()); - assertEquals(1, familyOptions.maxWriteBufferNumber()); - assertEquals(true, familyOptions.levelCompactionDynamicLevelBytes()); - rocksDB.close(); - } - - @Test - public void testReadChecksumTypeFromBookieConfiguration() throws Exception { - ServerConfiguration configuration = new ServerConfiguration(); - configuration.setEntryLocationRocksdbConf("entry_location_rocksdb.conf"); - File tmpDir = Files.createTempDirectory("bk-kv-rocksdbtest-conf").toFile(); - Files.createDirectory(Paths.get(tmpDir.toString(), "subDir")); - KeyValueStorageRocksDB rocksDB = new KeyValueStorageRocksDB(tmpDir.toString(), "subDir", - KeyValueStorageFactory.DbConfigType.EntryLocation, configuration); - assertNull(rocksDB.getColumnFamilyDescriptors()); - - Options options = (Options) rocksDB.getOptions(); - assertEquals(ChecksumType.kxxHash, ((BlockBasedTableConfig) options.tableFormatConfig()).checksumType()); - } - - //@Test - public void testReadChecksumTypeFromConfigurationFile() throws Exception { - ServerConfiguration configuration = new ServerConfiguration(); - URL url = getClass().getClassLoader().getResource("test_entry_location_rocksdb.conf"); - configuration.setEntryLocationRocksdbConf(url.getPath()); - File tmpDir = Files.createTempDirectory("bk-kv-rocksdbtest-file").toFile(); - Files.createDirectory(Paths.get(tmpDir.toString(), "subDir")); - KeyValueStorageRocksDB rocksDB = new KeyValueStorageRocksDB(tmpDir.toString(), "subDir", - KeyValueStorageFactory.DbConfigType.EntryLocation, configuration); - assertNotNull(rocksDB.getColumnFamilyDescriptors()); - - List columnFamilyDescriptorList = rocksDB.getColumnFamilyDescriptors(); - ColumnFamilyOptions familyOptions = columnFamilyDescriptorList.get(0).getOptions(); - // There is a bug in RocksDB, which can't load BlockedBasedTableConfig from Options file. - // https://github.com/facebook/rocksdb/issues/5297 - // After the PR: https://github.com/facebook/rocksdb/pull/10826 merge, we can turn on this test. - assertEquals(ChecksumType.kxxHash, ((BlockBasedTableConfig) familyOptions.tableFormatConfig()).checksumType()); - } - - @Test - public void testLevelCompactionDynamicLevelBytesFromConfigurationFile() throws Exception { - ServerConfiguration configuration = new ServerConfiguration(); - URL url = getClass().getClassLoader().getResource("conf/entry_location_rocksdb.conf"); - configuration.setEntryLocationRocksdbConf(url.getPath()); - File tmpDir = Files.createTempDirectory("bk-kv-rocksdbtest-file").toFile(); - Files.createDirectory(Paths.get(tmpDir.toString(), "subDir")); - KeyValueStorageRocksDB rocksDB = new KeyValueStorageRocksDB(tmpDir.toString(), "subDir", - KeyValueStorageFactory.DbConfigType.EntryLocation, configuration); - assertNotNull(rocksDB.getColumnFamilyDescriptors()); - - List columnFamilyDescriptorList = rocksDB.getColumnFamilyDescriptors(); - ColumnFamilyOptions familyOptions = columnFamilyDescriptorList.get(0).getOptions(); - assertEquals(true, familyOptions.levelCompactionDynamicLevelBytes()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageTest.java deleted file mode 100644 index d52f19305e1..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageTest.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map.Entry; -import org.apache.bookkeeper.bookie.storage.ldb.KeyValueStorage.Batch; -import org.apache.bookkeeper.bookie.storage.ldb.KeyValueStorage.CloseableIterator; -import org.apache.bookkeeper.bookie.storage.ldb.KeyValueStorageFactory.DbConfigType; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.commons.io.FileUtils; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * Unit test for {@link KeyValueStorage}. - */ -@RunWith(Parameterized.class) -public class KeyValueStorageTest { - - private final KeyValueStorageFactory storageFactory; - private final ServerConfiguration configuration; - - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { { KeyValueStorageRocksDB.factory } }); - } - - public KeyValueStorageTest(KeyValueStorageFactory storageFactory) { - this.storageFactory = storageFactory; - this.configuration = new ServerConfiguration(); - } - - private static long fromArray(byte[] array) { - return ArrayUtil.getLong(array, 0); - } - - private static byte[] toArray(long n) { - byte[] b = new byte[8]; - ArrayUtil.setLong(b, 0, n); - return b; - } - - @Test - public void simple() throws Exception { - File tmpDir = Files.createTempDirectory("junitTemporaryFolder").toFile(); - Files.createDirectory(Paths.get(tmpDir.toString(), "subDir")); - - KeyValueStorage db = storageFactory.newKeyValueStorage(tmpDir.toString(), "subDir", DbConfigType.Default, - configuration); - - assertEquals(null, db.getFloor(toArray(3))); - assertEquals(0, db.count()); - - db.put(toArray(5), toArray(5)); - - assertEquals(null, db.getFloor(toArray(3))); - assertEquals(1, db.count()); - - assertEquals(null, db.getFloor(toArray(5))); - assertEquals(5, fromArray(db.getFloor(toArray(6)).getKey())); - - db.put(toArray(3), toArray(3)); - - assertEquals(null, db.getFloor(toArray(3))); - assertEquals(2, db.count()); - - // // - - db.put(toArray(5), toArray(5)); - // Count can be imprecise - assertTrue(db.count() > 0); - - assertEquals(null, db.getFloor(toArray(1))); - assertEquals(null, db.getFloor(toArray(3))); - assertEquals(3, fromArray(db.getFloor(toArray(5)).getKey())); - assertEquals(5, fromArray(db.getFloor(toArray(6)).getKey())); - assertEquals(5, fromArray(db.getFloor(toArray(10)).getKey())); - - // Iterate - List foundKeys = Lists.newArrayList(); - try (CloseableIterator> iter = db.iterator()) { - while (iter.hasNext()) { - foundKeys.add(fromArray(iter.next().getKey())); - } - } - - assertEquals(Lists.newArrayList(3L, 5L), foundKeys); - - // Iterate over keys - foundKeys = Lists.newArrayList(); - CloseableIterator iter2 = db.keys(); - try { - while (iter2.hasNext()) { - foundKeys.add(fromArray(iter2.next())); - } - } finally { - iter2.close(); - } - - assertEquals(Lists.newArrayList(3L, 5L), foundKeys); - - // Scan with limits - foundKeys = Lists.newArrayList(); - iter2 = db.keys(toArray(1), toArray(4)); - try { - while (iter2.hasNext()) { - foundKeys.add(fromArray(iter2.next())); - } - } finally { - iter2.close(); - } - - assertEquals(Lists.newArrayList(3L), foundKeys); - - // Test deletion - db.put(toArray(10), toArray(10)); - db.put(toArray(11), toArray(11)); - db.put(toArray(12), toArray(12)); - db.put(toArray(14), toArray(14)); - - // Count can be imprecise - assertTrue(db.count() > 0); - - assertEquals(10L, fromArray(db.get(toArray(10)))); - db.delete(toArray(10)); - assertEquals(null, db.get(toArray(10))); - assertTrue(db.count() > 0); - - Batch batch = db.newBatch(); - batch.remove(toArray(11)); - batch.remove(toArray(12)); - batch.remove(toArray(13)); - batch.flush(); - assertEquals(null, db.get(toArray(11))); - assertEquals(null, db.get(toArray(12))); - assertEquals(null, db.get(toArray(13))); - assertEquals(14L, fromArray(db.get(toArray(14)))); - batch.close(); - - db.close(); - FileUtils.deleteDirectory(tmpDir); - } - - @Test - public void testBatch() throws Exception { - - configuration.setOperationMaxNumbersInSingleRocksDBWriteBatch(5); - - File tmpDir = Files.createTempDirectory("junitTemporaryFolder").toFile(); - Files.createDirectory(Paths.get(tmpDir.toString(), "subDir")); - - KeyValueStorage db = storageFactory.newKeyValueStorage(tmpDir.toString(), "subDir", DbConfigType.Default, - configuration); - - assertEquals(null, db.getFloor(toArray(3))); - assertEquals(0, db.count()); - - Batch batch = db.newBatch(); - assertEquals(0, batch.batchCount()); - - batch.put(toArray(1), toArray(1)); - batch.put(toArray(2), toArray(2)); - assertEquals(2, batch.batchCount()); - - batch.put(toArray(3), toArray(3)); - batch.put(toArray(4), toArray(4)); - batch.put(toArray(5), toArray(5)); - assertEquals(0, batch.batchCount()); - batch.put(toArray(6), toArray(6)); - assertEquals(1, batch.batchCount()); - - batch.flush(); - assertEquals(1, batch.batchCount()); - batch.close(); - assertEquals(0, batch.batchCount()); - - db.close(); - FileUtils.deleteDirectory(tmpDir); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexCheckOpTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexCheckOpTest.java deleted file mode 100644 index 41c80bf0319..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexCheckOpTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.List; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for class {@link LocationsIndexRebuildOp}. - */ -public class LedgersIndexCheckOpTest { - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - protected final TmpDirs tmpDirs = new TmpDirs(); - private String newDirectory() throws Exception { - File d = tmpDirs.createNew("bkTest", ".dir"); - d.delete(); - d.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(d); - BookieImpl.checkDirectoryStructure(curDir); - return d.getPath(); - } - - @Test - public void testMultiLedgerIndexDiffDirs() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { newDirectory(), newDirectory() }); - conf.setIndexDirName(new String[] { newDirectory(), newDirectory() }); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), diskChecker); - LedgerDirsManager indexDirsManager = new LedgerDirsManager(conf, conf.getIndexDirs(), diskChecker); - - DbLedgerStorage ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, indexDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - ledgerStorage.setCheckpointer(checkpointer); - ledgerStorage.setCheckpointSource(checkpointSource); - - // Insert some ledger & entries in the storage - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - ledgerStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - ledgerStorage.setFenced(ledgerId); - - for (long entryId = 0; entryId < 100; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ledgerStorage.addEntry(entry); - } - } - - ledgerStorage.flush(); - ledgerStorage.shutdown(); - - // ledgers index check - Assert.assertTrue(new LedgersIndexCheckOp(conf, true).initiate()); - - // clean data - List toDeleted = Lists.newArrayList(conf.getLedgerDirNames()); - toDeleted.addAll(Lists.newArrayList(conf.getIndexDirNames())); - toDeleted.forEach(d -> { - try { - FileUtils.forceDelete(new File(d)); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildOpTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildOpTest.java deleted file mode 100644 index 0e99c28998e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildOpTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.List; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for class {@link LocationsIndexRebuildOp}. - */ -public class LedgersIndexRebuildOpTest { - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - protected final TmpDirs tmpDirs = new TmpDirs(); - private String newDirectory() throws Exception { - File d = tmpDirs.createNew("bkTest", ".dir"); - d.delete(); - d.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(d); - BookieImpl.checkDirectoryStructure(curDir); - return d.getPath(); - } - - @Test - public void testMultiLedgerIndexDiffDirs() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { newDirectory(), newDirectory() }); - conf.setIndexDirName(new String[] { newDirectory(), newDirectory() }); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), diskChecker); - LedgerDirsManager indexDirsManager = new LedgerDirsManager(conf, conf.getIndexDirs(), diskChecker); - - DbLedgerStorage ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, indexDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - ledgerStorage.setCheckpointer(checkpointer); - ledgerStorage.setCheckpointSource(checkpointSource); - - // Insert some ledger & entries in the storage - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - ledgerStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - ledgerStorage.setFenced(ledgerId); - - for (long entryId = 0; entryId < 100; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ledgerStorage.addEntry(entry); - } - } - - ledgerStorage.flush(); - ledgerStorage.shutdown(); - - // Rebuild index through the tool - Assert.assertTrue(new LedgersIndexRebuildOp(conf, true).initiate()); - - // clean test data - List toDeleted = Lists.newArrayList(conf.getLedgerDirNames()); - toDeleted.addAll(Lists.newArrayList(conf.getIndexDirNames())); - toDeleted.forEach(d -> { - try { - FileUtils.forceDelete(new File(d)); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildTest.java deleted file mode 100644 index f955f713bd6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.UUID; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieShell; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Test for class {@link LedgersIndexRebuildOp}. - */ -@RunWith(MockitoJUnitRunner.class) -public class LedgersIndexRebuildTest { - - private final BookieId bookieAddress = BookieId.parse(UUID.randomUUID().toString()); - private ServerConfiguration conf; - private File tmpDir; - - @Before - public void setUp() throws IOException { - tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - System.out.println(tmpDir); - } - - @After - public void tearDown() throws IOException { - FileUtils.forceDelete(tmpDir); - } - - @Test - public void testRebuildIncludesAllLedgersAndSetToFenced() throws Exception { - byte[] masterKey = "12345".getBytes(); - long ledgerCount = 100; - - // no attempts to get ledger metadata fail - DbLedgerStorage ledgerStorage = setupLedgerStorage(); - - // Insert some ledger & entries in the storage - for (long ledgerId = 0; ledgerId < ledgerCount; ledgerId++) { - ledgerStorage.setMasterKey(ledgerId, masterKey); - - for (long entryId = 0; entryId < 2; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ledgerStorage.addEntry(entry); - } - } - - ledgerStorage.flush(); - ledgerStorage.shutdown(); - - // Rebuild index through the tool - BookieShell shell = new BookieShell(); - shell.setConf(conf); - int res = shell.run(new String[] { "rebuild-db-ledgers-index", "-v" }); - - Assert.assertEquals(0, res); - - // Verify that the ledgers index has the ledgers and that they are fenced - ledgerStorage = new DbLedgerStorage(); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - ledgerStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - - for (long ledgerId = 0; ledgerId < ledgerCount; ledgerId++) { - assertTrue(ledgerStorage.ledgerExists(ledgerId)); - assertTrue(ledgerStorage.isFenced(ledgerId)); - } - - ledgerStorage.shutdown(); - } - - private DbLedgerStorage setupLedgerStorage() throws Exception { - conf = TestBKConfiguration.newServerConfiguration(); - conf.setBookieId(bookieAddress.getId()); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DbLedgerStorage ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - - return ledgerStorage; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LocationsIndexRebuildTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LocationsIndexRebuildTest.java deleted file mode 100644 index 318f088af97..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LocationsIndexRebuildTest.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Set; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieShell; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TmpDirs; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for class {@link LocationsIndexRebuildOp}. - */ -public class LocationsIndexRebuildTest { - - CheckpointSource checkpointSource = new CheckpointSource() { - @Override - public Checkpoint newCheckpoint() { - return Checkpoint.MAX; - } - - @Override - public void checkpointComplete(Checkpoint checkpoint, boolean compact) throws IOException { - } - }; - - Checkpointer checkpointer = new Checkpointer() { - @Override - public void startCheckpoint(Checkpoint checkpoint) { - // No-op - } - - @Override - public void start() { - // no-op - } - }; - - protected final TmpDirs tmpDirs = new TmpDirs(); - private String newDirectory() throws Exception { - File d = tmpDirs.createNew("bkTest", ".dir"); - d.delete(); - d.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(d); - BookieImpl.checkDirectoryStructure(curDir); - return d.getPath(); - } - - @Test - public void test() throws Exception { - File tmpDir = File.createTempFile("bkTest", ".dir"); - tmpDir.delete(); - tmpDir.mkdir(); - File curDir = BookieImpl.getCurrentDirectory(tmpDir); - BookieImpl.checkDirectoryStructure(curDir); - - System.out.println(tmpDir); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { tmpDir.toString() }); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), - new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold())); - - DbLedgerStorage ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - ledgerStorage.setCheckpointer(checkpointer); - ledgerStorage.setCheckpointSource(checkpointSource); - - // Insert some ledger & entries in the storage - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - ledgerStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - ledgerStorage.setFenced(ledgerId); - - for (long entryId = 0; entryId < 100; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ledgerStorage.addEntry(entry); - } - } - - ledgerStorage.flush(); - ledgerStorage.shutdown(); - - // Rebuild index through the tool - BookieShell shell = new BookieShell(); - shell.setConf(conf); - int res = shell.run(new String[] { "rebuild-db-ledger-locations-index" }); - - Assert.assertEquals(0, res); - - // Verify that db index has the same entries - ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, ledgerDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - ledgerStorage.setCheckpointSource(checkpointSource); - ledgerStorage.setCheckpointer(checkpointer); - - Set ledgers = Sets.newTreeSet(ledgerStorage.getActiveLedgersInRange(0, Long.MAX_VALUE)); - Assert.assertEquals(Sets.newTreeSet(Lists.newArrayList(0L, 1L, 2L, 3L, 4L)), ledgers); - - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - Assert.assertEquals(true, ledgerStorage.isFenced(ledgerId)); - Assert.assertEquals("ledger-" + ledgerId, new String(ledgerStorage.readMasterKey(ledgerId))); - - ByteBuf lastEntry = ledgerStorage.getLastEntry(ledgerId); - assertEquals(ledgerId, lastEntry.readLong()); - long lastEntryId = lastEntry.readLong(); - assertEquals(99, lastEntryId); - - for (long entryId = 0; entryId < 100; entryId++) { - ByteBuf entry = Unpooled.buffer(1024); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ByteBuf result = ledgerStorage.getEntry(ledgerId, entryId); - Assert.assertEquals(entry, result); - } - } - - ledgerStorage.shutdown(); - FileUtils.forceDelete(tmpDir); - } - - @Test - public void testMultiLedgerIndexDiffDirs() throws Exception { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setLedgerDirNames(new String[] { newDirectory(), newDirectory() }); - conf.setIndexDirName(new String[] { newDirectory(), newDirectory() }); - conf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - DiskChecker diskChecker = new DiskChecker(conf.getDiskUsageThreshold(), conf.getDiskUsageWarnThreshold()); - LedgerDirsManager ledgerDirsManager = new LedgerDirsManager(conf, conf.getLedgerDirs(), diskChecker); - LedgerDirsManager indexDirsManager = new LedgerDirsManager(conf, conf.getIndexDirs(), diskChecker); - - DbLedgerStorage ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, indexDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - ledgerStorage.setCheckpointer(checkpointer); - ledgerStorage.setCheckpointSource(checkpointSource); - - // Insert some ledger & entries in the storage - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - ledgerStorage.setMasterKey(ledgerId, ("ledger-" + ledgerId).getBytes()); - ledgerStorage.setFenced(ledgerId); - - for (long entryId = 0; entryId < 100; entryId++) { - ByteBuf entry = Unpooled.buffer(128); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ledgerStorage.addEntry(entry); - } - } - - ledgerStorage.flush(); - ledgerStorage.shutdown(); - - // Rebuild index through the tool - new LocationsIndexRebuildOp(conf).initiate(); - - // Verify that db index has the same entries - ledgerStorage = new DbLedgerStorage(); - ledgerStorage.initialize(conf, null, ledgerDirsManager, indexDirsManager, - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT); - ledgerStorage.setCheckpointSource(checkpointSource); - ledgerStorage.setCheckpointer(checkpointer); - - Set ledgers = Sets.newTreeSet(ledgerStorage.getActiveLedgersInRange(0, Long.MAX_VALUE)); - Assert.assertEquals(Sets.newTreeSet(Lists.newArrayList(0L, 1L, 2L, 3L, 4L)), ledgers); - - for (long ledgerId = 0; ledgerId < 5; ledgerId++) { - Assert.assertEquals(true, ledgerStorage.isFenced(ledgerId)); - Assert.assertEquals("ledger-" + ledgerId, new String(ledgerStorage.readMasterKey(ledgerId))); - - ByteBuf lastEntry = ledgerStorage.getLastEntry(ledgerId); - assertEquals(ledgerId, lastEntry.readLong()); - long lastEntryId = lastEntry.readLong(); - assertEquals(99, lastEntryId); - - for (long entryId = 0; entryId < 100; entryId++) { - ByteBuf entry = Unpooled.buffer(1024); - entry.writeLong(ledgerId); - entry.writeLong(entryId); - entry.writeBytes(("entry-" + entryId).getBytes()); - - ByteBuf result = ledgerStorage.getEntry(ledgerId, entryId); - Assert.assertEquals(entry, result); - } - } - - ledgerStorage.shutdown(); - List toDeleted = Lists.newArrayList(conf.getLedgerDirNames()); - toDeleted.addAll(Lists.newArrayList(conf.getIndexDirNames())); - toDeleted.forEach(d -> { - try { - FileUtils.forceDelete(new File(d)); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/PersistentEntryLogMetadataMapTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/PersistentEntryLogMetadataMapTest.java deleted file mode 100644 index 1f5d52d6dc3..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/PersistentEntryLogMetadataMapTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.io.File; -import java.util.List; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.EntryLogMetadata; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test for {@link PersistentEntryLogMetadataMap}. - */ -public class PersistentEntryLogMetadataMapTest { - - private final ServerConfiguration configuration; - - @Rule - public TemporaryFolder tempFolder = new TemporaryFolder(); - - public PersistentEntryLogMetadataMapTest() { - this.configuration = new ServerConfiguration(); - } - - /** - * Validates PersistentEntryLogMetadataMap functionalities. - * - * @throws Exception - */ - @Test - public void simple() throws Exception { - File tmpDir = tempFolder.newFolder("metadata-cache"); - String path = tmpDir.getAbsolutePath(); - PersistentEntryLogMetadataMap entryMetadataMap = new PersistentEntryLogMetadataMap(path, configuration); - - List metadatas = Lists.newArrayList(); - int totalMetadata = 1000; - // insert entry-log-metadata records - for (int i = 1; i <= totalMetadata; i++) { - EntryLogMetadata entryLogMeta = createEntryLogMetadata(i, i); - metadatas.add(entryLogMeta); - entryMetadataMap.put(i, entryLogMeta); - } - for (int i = 1; i <= totalMetadata; i++) { - assertTrue(entryMetadataMap.containsKey(i)); - } - - assertEquals(entryMetadataMap.size(), totalMetadata); - - entryMetadataMap.forEach((logId, metadata) -> { - assertEquals(metadatas.get(logId.intValue() - 1).getTotalSize(), metadata.getTotalSize()); - for (int i = 0; i < logId.intValue(); i++) { - assertTrue(metadata.containsLedger(i)); - } - }); - - metadatas.forEach(meta -> { - long logId = meta.getEntryLogId(); - try { - entryMetadataMap.forKey(logId, (entryLogId, persistedMeta) -> { - assertEquals(meta.getEntryLogId(), persistedMeta.getEntryLogId()); - assertEquals(meta.getTotalSize(), persistedMeta.getTotalSize()); - assertEquals(logId, (long) entryLogId); - }); - } catch (BookieException.EntryLogMetadataMapException e) { - throw new RuntimeException(e); - } - }); - - // remove entry-log entry - for (int i = 1; i <= totalMetadata; i++) { - entryMetadataMap.remove(i); - } - - // entries should not be present into map - for (int i = 1; i <= totalMetadata; i++) { - assertFalse(entryMetadataMap.containsKey(i)); - } - - assertEquals(entryMetadataMap.size(), 0); - - entryMetadataMap.close(); - } - - /** - * Validates PersistentEntryLogMetadataMap persists metadata state in - * rocksDB. - * - * @throws Exception - */ - @Test - public void closeAndOpen() throws Exception { - File tmpDir = tempFolder.newFolder(); - String path = tmpDir.getAbsolutePath(); - PersistentEntryLogMetadataMap entryMetadataMap = new PersistentEntryLogMetadataMap(path, configuration); - - List metadatas = Lists.newArrayList(); - int totalMetadata = 1000; - for (int i = 1; i <= totalMetadata; i++) { - EntryLogMetadata entryLogMeta = createEntryLogMetadata(i, i); - metadatas.add(entryLogMeta); - entryMetadataMap.put(i, entryLogMeta); - } - for (int i = 1; i <= totalMetadata; i++) { - assertTrue(entryMetadataMap.containsKey(i)); - } - - // close metadata-map - entryMetadataMap.close(); - // Open it again - entryMetadataMap = new PersistentEntryLogMetadataMap(path, configuration); - - entryMetadataMap.forEach((logId, metadata) -> { - assertEquals(metadatas.get(logId.intValue() - 1).getTotalSize(), logId.longValue()); - for (int i = 0; i < logId.intValue(); i++) { - assertTrue(metadata.containsLedger(i)); - } - }); - - entryMetadataMap.close(); - } - - private EntryLogMetadata createEntryLogMetadata(long logId, long totalLedgers) { - EntryLogMetadata metadata = new EntryLogMetadata(logId); - for (int i = 0; i < totalLedgers; i++) { - metadata.addLedgerSize(i, 1); - } - return metadata; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ReadCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ReadCacheTest.java deleted file mode 100644 index ad846c6212b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ReadCacheTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import org.junit.Test; - -/** - * Unit test for {@link ReadCache}. - */ -public class ReadCacheTest { - - @Test - public void simple() { - ReadCache cache = new ReadCache(UnpooledByteBufAllocator.DEFAULT, 10 * 1024); - - assertEquals(0, cache.count()); - assertEquals(0, cache.size()); - - ByteBuf entry = Unpooled.wrappedBuffer(new byte[1024]); - cache.put(1, 0, entry); - - assertEquals(1, cache.count()); - assertEquals(1024, cache.size()); - - assertEquals(entry, cache.get(1, 0)); - assertNull(cache.get(1, 1)); - - for (int i = 1; i < 10; i++) { - cache.put(1, i, entry); - } - - assertEquals(10, cache.count()); - assertEquals(10 * 1024, cache.size()); - - cache.put(1, 10, entry); - - // First half of entries will have been evicted - for (int i = 0; i < 5; i++) { - assertNull(cache.get(1, i)); - } - - for (int i = 5; i < 11; i++) { - assertEquals(entry, cache.get(1, i)); - } - - cache.close(); - } - - @Test - public void emptyCache() { - ReadCache cache = new ReadCache(UnpooledByteBufAllocator.DEFAULT, 10 * 1024); - - assertEquals(0, cache.count()); - assertEquals(0, cache.size()); - assertEquals(null, cache.get(0, 0)); - - cache.close(); - } - - @Test - public void multipleSegments() { - // Test with multiple smaller segments - ReadCache cache = new ReadCache(UnpooledByteBufAllocator.DEFAULT, 10 * 1024, 2 * 1024); - - assertEquals(0, cache.count()); - assertEquals(0, cache.size()); - - for (int i = 0; i < 10; i++) { - ByteBuf entry = Unpooled.wrappedBuffer(new byte[1024]); - entry.setInt(0, i); - cache.put(1, i, entry); - } - - for (int i = 0; i < 10; i++) { - ByteBuf res = cache.get(1, i); - assertEquals(1, res.refCnt()); - - assertEquals(1024, res.readableBytes()); - assertEquals(i, res.getInt(0)); - } - - assertEquals(10, cache.count()); - assertEquals(10 * 1024, cache.size()); - - // Putting one more entry, should trigger the 1st segment rollover - ByteBuf entry = Unpooled.wrappedBuffer(new byte[1024]); - cache.put(2, 0, entry); - - assertEquals(9, cache.count()); - assertEquals(9 * 1024, cache.size()); - - cache.close(); - } - - @Test - public void testHasEntry() { - ReadCache cache = new ReadCache(UnpooledByteBufAllocator.DEFAULT, 10 * 1024, 2 * 1024); - - long ledgerId = 0xfefe; - for (int i = 0; i < 10; i++) { - ByteBuf entry = Unpooled.wrappedBuffer(new byte[1024]); - entry.setInt(0, i); - cache.put(ledgerId, i, entry); - } - - assertFalse(cache.hasEntry(0xdead, 0)); - assertFalse(cache.hasEntry(ledgerId, -1)); - for (int i = 0; i < 10; i++) { - assertTrue(cache.hasEntry(ledgerId, i)); - } - assertFalse(cache.hasEntry(ledgerId, 10)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/WriteCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/WriteCacheTest.java deleted file mode 100644 index 9ac84984b62..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/WriteCacheTest.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.bookie.storage.ldb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.util.ReferenceCountUtil; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import org.junit.Test; - -/** - * Unit test for {@link WriteCache}. - */ -public class WriteCacheTest { - - private static final ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT; - - @Test - public void simple() throws Exception { - WriteCache cache = new WriteCache(allocator, 10 * 1024); - - ByteBuf entry1 = allocator.buffer(1024); - ByteBufUtil.writeUtf8(entry1, "entry-1"); - entry1.writerIndex(entry1.capacity()); - - assertTrue(cache.isEmpty()); - assertEquals(0, cache.count()); - assertEquals(0, cache.size()); - - cache.put(1, 1, entry1); - - assertFalse(cache.isEmpty()); - assertEquals(1, cache.count()); - assertEquals(entry1.readableBytes(), cache.size()); - - assertEquals(entry1, cache.get(1, 1)); - assertNull(cache.get(1, 2)); - assertNull(cache.get(2, 1)); - - assertEquals(entry1, cache.getLastEntry(1)); - assertEquals(null, cache.getLastEntry(2)); - - cache.clear(); - - assertTrue(cache.isEmpty()); - assertEquals(0, cache.count()); - assertEquals(0, cache.size()); - - ReferenceCountUtil.release(entry1); - cache.close(); - } - - @Test - public void cacheFull() throws Exception { - int cacheSize = 10 * 1024; - int entrySize = 1024; - int entriesCount = cacheSize / entrySize; - - WriteCache cache = new WriteCache(allocator, cacheSize); - - ByteBuf entry = allocator.buffer(entrySize); - entry.writerIndex(entry.capacity()); - - for (int i = 0; i < entriesCount; i++) { - assertTrue(cache.put(1, i, entry)); - } - - assertFalse(cache.put(1, 11, entry)); - - assertFalse(cache.isEmpty()); - assertEquals(entriesCount, cache.count()); - assertEquals(cacheSize, cache.size()); - - AtomicInteger findCount = new AtomicInteger(0); - cache.forEach((ledgerId, entryId, data) -> { - findCount.incrementAndGet(); - }); - - assertEquals(entriesCount, findCount.get()); - - cache.deleteLedger(1); - - findCount.set(0); - cache.forEach((ledgerId, entryId, data) -> { - findCount.incrementAndGet(); - }); - - assertEquals(0, findCount.get()); - - ReferenceCountUtil.release(entry); - cache.close(); - } - - @Test - public void testMultipleSegments() { - // Create cache with max size 1Mb and each segment is 16Kb - WriteCache cache = new WriteCache(allocator, 1024 * 1024, 16 * 1024); - - ByteBuf entry = Unpooled.buffer(1024); - entry.writerIndex(entry.capacity()); - - for (int i = 0; i < 48; i++) { - cache.put(1, i, entry); - } - - assertEquals(48, cache.count()); - assertEquals(48 * 1024, cache.size()); - - cache.close(); - } - - @Test - public void testEmptyCache() throws IOException { - WriteCache cache = new WriteCache(allocator, 1024 * 1024, 16 * 1024); - - assertEquals(0, cache.count()); - assertEquals(0, cache.size()); - assertTrue(cache.isEmpty()); - - AtomicLong foundEntries = new AtomicLong(); - cache.forEach((ledgerId, entryId, entry) -> { - foundEntries.incrementAndGet(); - }); - - assertEquals(0, foundEntries.get()); - cache.close(); - } - - @Test - public void testMultipleWriters() throws Exception { - // Create cache with max size 1Mb and each segment is 16Kb - WriteCache cache = new WriteCache(allocator, 10 * 1024 * 1024, 16 * 1024); - - ExecutorService executor = Executors.newCachedThreadPool(); - - int numThreads = 10; - int entriesPerThread = 10 * 1024 / numThreads; - - CyclicBarrier barrier = new CyclicBarrier(numThreads); - CountDownLatch latch = new CountDownLatch(numThreads); - - for (int i = 0; i < numThreads; i++) { - int ledgerId = i; - - executor.submit(() -> { - try { - barrier.await(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw new RuntimeException(ie); - } catch (BrokenBarrierException e) { - throw new RuntimeException(e); - } - - ByteBuf entry = Unpooled.buffer(1024); - entry.writerIndex(entry.capacity()); - - for (int entryId = 0; entryId < entriesPerThread; entryId++) { - assertTrue(cache.put(ledgerId, entryId, entry)); - } - - latch.countDown(); - }); - } - - // Wait for all tasks to be completed - latch.await(); - - // assertEquals(numThreads * entriesPerThread, cache.count()); - assertEquals(cache.count() * 1024, cache.size()); - - // Verify entries by iterating over write cache - AtomicLong currentLedgerId = new AtomicLong(0); - AtomicLong currentEntryId = new AtomicLong(0); - - cache.forEach((ledgerId, entryId, entry) -> { - assertEquals(currentLedgerId.get(), ledgerId); - assertEquals(currentEntryId.get(), entryId); - - if (currentEntryId.incrementAndGet() == entriesPerThread) { - currentLedgerId.incrementAndGet(); - currentEntryId.set(0); - } - }); - - cache.close(); - executor.shutdown(); - } - - @Test - public void testLedgerDeletion() throws IOException { - WriteCache cache = new WriteCache(allocator, 1024 * 1024, 16 * 1024); - - ByteBuf entry = Unpooled.buffer(1024); - entry.writerIndex(entry.capacity()); - - for (long ledgerId = 0; ledgerId < 10; ledgerId++) { - for (int entryId = 0; entryId < 10; entryId++) { - cache.put(ledgerId, entryId, entry); - } - } - - assertEquals(100, cache.count()); - assertEquals(100 * 1024, cache.size()); - - cache.deleteLedger(5); - - // Entries are not immediately deleted, just ignored on scan - assertEquals(100, cache.count()); - assertEquals(100 * 1024, cache.size()); - - // Verify entries by iterating over write cache - AtomicLong currentLedgerId = new AtomicLong(0); - AtomicLong currentEntryId = new AtomicLong(0); - - cache.forEach((ledgerId, entryId, e) -> { - assertEquals(currentLedgerId.get(), ledgerId); - assertEquals(currentEntryId.get(), entryId); - - if (currentEntryId.incrementAndGet() == 10) { - currentLedgerId.incrementAndGet(); - currentEntryId.set(0); - - if (currentLedgerId.get() == 5) { - // Ledger 5 was deleted - currentLedgerId.incrementAndGet(); - } - } - }); - - cache.close(); - } - - @Test - public void testWriteReadsInMultipleSegments() { - // Create cache with max size 4 KB and each segment is 128 bytes - WriteCache cache = new WriteCache(allocator, 4 * 1024, 128); - - for (int i = 0; i < 48; i++) { - boolean inserted = cache.put(1, i, Unpooled.wrappedBuffer(("test-" + i).getBytes())); - assertTrue(inserted); - } - - assertEquals(48, cache.count()); - - for (int i = 0; i < 48; i++) { - ByteBuf b = cache.get(1, i); - - assertEquals("test-" + i, b.toString(Charset.forName("UTF-8"))); - } - - cache.close(); - } - - @Test - public void testHasEntry() { - // Create cache with max size 4 KB and each segment is 128 bytes - WriteCache cache = new WriteCache(allocator, 4 * 1024, 128); - - long ledgerId = 0xdede; - for (int i = 0; i < 48; i++) { - boolean inserted = cache.put(ledgerId, i, Unpooled.wrappedBuffer(("test-" + i).getBytes())); - assertTrue(inserted); - } - - assertEquals(48, cache.count()); - - assertFalse(cache.hasEntry(0xfede, 1)); - assertFalse(cache.hasEntry(ledgerId, -1)); - for (int i = 0; i < 48; i++) { - assertTrue(cache.hasEntry(ledgerId, i)); - } - assertFalse(cache.hasEntry(ledgerId, 48)); - } - - @Test(expected = IOException.class) - public void testForEachIOException() throws Exception { - try (WriteCache cache = new WriteCache(allocator, 1024 * 1024, 16 * 1024)) { - - for (int i = 0; i < 48; i++) { - boolean inserted = cache.put(1, i, Unpooled.wrappedBuffer(("test-" + i).getBytes())); - assertTrue(inserted); - } - - assertEquals(48, cache.count()); - - cache.forEach(((ledgerId, entryId, entry) -> { - throw new IOException("test throw IOException."); - })); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BKExceptionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BKExceptionTest.java deleted file mode 100644 index fb293924d3f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BKExceptionTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import java.util.concurrent.CompletionException; -import java.util.concurrent.ExecutionException; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for extracting codes from BKException. - */ -public class BKExceptionTest { - @Test - public void testBKExceptionCode() { - Assert.assertEquals(BKException.Code.WriteException, - BKException.getExceptionCode(new BKException.BKWriteException(), - BKException.Code.ReadException)); - } - - @Test - public void testNonBKExceptionCode() { - Assert.assertEquals(BKException.Code.ReadException, - BKException.getExceptionCode(new Exception(), - BKException.Code.ReadException)); - - } - - @Test - public void testNestedBKExceptionCode() { - Assert.assertEquals(BKException.Code.WriteException, - BKException.getExceptionCode( - new ExecutionException("test", new BKException.BKWriteException()), - BKException.Code.ReadException)); - } - - @Test - public void testDoubleNestedBKExceptionCode() { - Assert.assertEquals(BKException.Code.WriteException, - BKException.getExceptionCode( - new ExecutionException("test", - new CompletionException("blah", - new BKException.BKWriteException())), - BKException.Code.ReadException)); - - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java deleted file mode 100644 index e776aea707d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java +++ /dev/null @@ -1,756 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.util.BookKeeperConstants.AVAILABLE_NODE; -import static org.apache.bookkeeper.util.BookKeeperConstants.READONLY; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.net.InetAddresses; -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieResources; -import org.apache.bookkeeper.bookie.CookieValidation; -import org.apache.bookkeeper.bookie.LegacyCookieValidation; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.component.ComponentStarter; -import org.apache.bookkeeper.common.component.Lifecycle; -import org.apache.bookkeeper.common.component.LifecycleComponent; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.BookieServiceInfo; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.UnderreplicatedLedger; -import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.replication.ReplicationException.UnavailableException; -import org.apache.bookkeeper.server.Main; -import org.apache.bookkeeper.server.conf.BookieConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.AvailabilityOfEntriesOfLedger; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.util.PortManager; -import org.apache.commons.io.FileUtils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs.Ids; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the bookkeeper admin. - */ -public class BookKeeperAdminTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(BookKeeperAdminTest.class); - private DigestType digestType = DigestType.CRC32; - private static final String PASSWORD = "testPasswd"; - private static final int numOfBookies = 2; - private final int lostBookieRecoveryDelayInitValue = 1800; - - public BookKeeperAdminTest() { - super(numOfBookies, 480); - baseConf.setLostBookieRecoveryDelay(lostBookieRecoveryDelayInitValue); - baseConf.setOpenLedgerRereplicationGracePeriod(String.valueOf(30000)); - setAutoRecoveryEnabled(true); - } - - @Test - public void testLostBookieRecoveryDelayValue() throws Exception { - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - assertEquals("LostBookieRecoveryDelay", - lostBookieRecoveryDelayInitValue, bkAdmin.getLostBookieRecoveryDelay()); - int newLostBookieRecoveryDelayValue = 2400; - bkAdmin.setLostBookieRecoveryDelay(newLostBookieRecoveryDelayValue); - assertEquals("LostBookieRecoveryDelay", - newLostBookieRecoveryDelayValue, bkAdmin.getLostBookieRecoveryDelay()); - newLostBookieRecoveryDelayValue = 3000; - bkAdmin.setLostBookieRecoveryDelay(newLostBookieRecoveryDelayValue); - assertEquals("LostBookieRecoveryDelay", - newLostBookieRecoveryDelayValue, bkAdmin.getLostBookieRecoveryDelay()); - LOG.info("Test Done"); - } - } - - @Test - public void testTriggerAuditWithStoreSystemTimeAsLedgerUnderreplicatedMarkTime() throws Exception { - testTriggerAudit(true); - } - - @Test - public void testTriggerAuditWithoutStoreSystemTimeAsLedgerUnderreplicatedMarkTime() throws Exception { - testTriggerAudit(false); - } - - public void testTriggerAudit(boolean storeSystemTimeAsLedgerUnderreplicatedMarkTime) throws Exception { - restartBookies(c -> { - c.setStoreSystemTimeAsLedgerUnderreplicatedMarkTime(storeSystemTimeAsLedgerUnderreplicatedMarkTime); - return c; - }); - ClientConfiguration thisClientConf = new ClientConfiguration(baseClientConf); - thisClientConf - .setStoreSystemTimeAsLedgerUnderreplicatedMarkTime(storeSystemTimeAsLedgerUnderreplicatedMarkTime); - long testStartSystime = System.currentTimeMillis(); - ZkLedgerUnderreplicationManager urLedgerMgr = new ZkLedgerUnderreplicationManager(thisClientConf, zkc); - BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString()); - int lostBookieRecoveryDelayValue = bkAdmin.getLostBookieRecoveryDelay(); - urLedgerMgr.disableLedgerReplication(); - try { - bkAdmin.triggerAudit(); - fail("Trigger Audit should have failed because LedgerReplication is disabled"); - } catch (UnavailableException une) { - // expected - } - assertEquals("LostBookieRecoveryDelay", lostBookieRecoveryDelayValue, bkAdmin.getLostBookieRecoveryDelay()); - urLedgerMgr.enableLedgerReplication(); - bkAdmin.triggerAudit(); - assertEquals("LostBookieRecoveryDelay", lostBookieRecoveryDelayValue, bkAdmin.getLostBookieRecoveryDelay()); - long ledgerId = 1L; - LedgerHandle ledgerHandle = bkc.createLedgerAdv(ledgerId, numBookies, numBookies, numBookies, digestType, - PASSWORD.getBytes(), null); - ledgerHandle.addEntry(0, "data".getBytes()); - ledgerHandle.close(); - - BookieServer bookieToKill = serverByIndex(1); - killBookie(1); - /* - * since lostBookieRecoveryDelay is set, when a bookie is died, it will - * not start Audit process immediately. But when triggerAudit is called - * it will force audit process. - */ - bkAdmin.triggerAudit(); - Thread.sleep(500); - Iterator underreplicatedLedgerItr = urLedgerMgr.listLedgersToRereplicate(null); - assertTrue("There are supposed to be underreplicatedledgers", underreplicatedLedgerItr.hasNext()); - UnderreplicatedLedger underreplicatedLedger = underreplicatedLedgerItr.next(); - assertEquals("Underreplicated ledgerId", ledgerId, underreplicatedLedger.getLedgerId()); - assertTrue("Missingreplica of Underreplicated ledgerId should contain " + bookieToKill, - underreplicatedLedger.getReplicaList().contains(bookieToKill.getBookieId().getId())); - if (storeSystemTimeAsLedgerUnderreplicatedMarkTime) { - long ctimeOfURL = underreplicatedLedger.getCtime(); - assertTrue("ctime of underreplicated ledger should be greater than test starttime", - (ctimeOfURL > testStartSystime) && (ctimeOfURL < System.currentTimeMillis())); - } else { - assertEquals("ctime of underreplicated ledger should not be set", UnderreplicatedLedger.UNASSIGNED_CTIME, - underreplicatedLedger.getCtime()); - } - bkAdmin.close(); - } - - @Test - public void testBookieInit() throws Exception { - ServerConfiguration confOfExistingBookie = newServerConfiguration(); - BookieId bookieId = BookieImpl.getBookieId(confOfExistingBookie); - try (MetadataBookieDriver driver = BookieResources.createMetadataDriver( - confOfExistingBookie, NullStatsLogger.INSTANCE); - RegistrationManager rm = driver.createRegistrationManager()) { - CookieValidation cookieValidation = new LegacyCookieValidation(confOfExistingBookie, rm); - cookieValidation.checkCookies(Main.storageDirectoriesFromConf(confOfExistingBookie)); - rm.registerBookie(bookieId, false /* readOnly */, BookieServiceInfo.EMPTY); - Assert.assertFalse( - "initBookie shouldn't have succeeded, since bookie is still running with that configuration", - BookKeeperAdmin.initBookie(confOfExistingBookie)); - } - - Assert.assertFalse("initBookie shouldn't have succeeded, since previous bookie is not formatted yet completely", - BookKeeperAdmin.initBookie(confOfExistingBookie)); - - File[] ledgerDirs = confOfExistingBookie.getLedgerDirs(); - for (File ledgerDir : ledgerDirs) { - FileUtils.deleteDirectory(ledgerDir); - } - Assert.assertFalse("initBookie shouldn't have succeeded, since previous bookie is not formatted yet completely", - BookKeeperAdmin.initBookie(confOfExistingBookie)); - - File[] indexDirs = confOfExistingBookie.getIndexDirs(); - if (indexDirs != null) { - for (File indexDir : indexDirs) { - FileUtils.deleteDirectory(indexDir); - } - } - Assert.assertFalse("initBookie shouldn't have succeeded, since cookie in ZK is not deleted yet", - BookKeeperAdmin.initBookie(confOfExistingBookie)); - String bookieCookiePath = - ZKMetadataDriverBase.resolveZkLedgersRootPath(confOfExistingBookie) - + "/" + BookKeeperConstants.COOKIE_NODE - + "/" + bookieId.toString(); - zkc.delete(bookieCookiePath, -1); - - Assert.assertTrue("initBookie shouldn't succeeded", - BookKeeperAdmin.initBookie(confOfExistingBookie)); - } - - @Test - public void testInitNewCluster() throws Exception { - ServerConfiguration newConfig = new ServerConfiguration(baseConf); - String ledgersRootPath = "/testledgers"; - newConfig.setMetadataServiceUri(newMetadataServiceUri(ledgersRootPath)); - Assert.assertTrue("New cluster should be initialized successfully", BookKeeperAdmin.initNewCluster(newConfig)); - - Assert.assertTrue("Cluster rootpath should have been created successfully " + ledgersRootPath, - (zkc.exists(ledgersRootPath, false) != null)); - String availableBookiesPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) + "/" + AVAILABLE_NODE; - Assert.assertTrue("AvailableBookiesPath should have been created successfully " + availableBookiesPath, - (zkc.exists(availableBookiesPath, false) != null)); - String readonlyBookiesPath = availableBookiesPath + "/" + READONLY; - Assert.assertTrue("ReadonlyBookiesPath should have been created successfully " + readonlyBookiesPath, - (zkc.exists(readonlyBookiesPath, false) != null)); - String instanceIdPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) - + "/" + BookKeeperConstants.INSTANCEID; - Assert.assertTrue("InstanceId node should have been created successfully" + instanceIdPath, - (zkc.exists(instanceIdPath, false) != null)); - - String ledgersLayout = ledgersRootPath + "/" + BookKeeperConstants.LAYOUT_ZNODE; - Assert.assertTrue("Layout node should have been created successfully" + ledgersLayout, - (zkc.exists(ledgersLayout, false) != null)); - - /** - * create znodes simulating existence of Bookies in the cluster - */ - int numOfBookies = 3; - Random rand = new Random(); - for (int i = 0; i < numOfBookies; i++) { - String ipString = InetAddresses.fromInteger(rand.nextInt()).getHostAddress(); - String regPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) - + "/" + AVAILABLE_NODE + "/" + ipString + ":3181"; - zkc.create(regPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); - } - - /* - * now it should be possible to create ledger and delete the same - */ - BookKeeper bk = new BookKeeper(new ClientConfiguration(newConfig)); - LedgerHandle lh = bk.createLedger(numOfBookies, numOfBookies, numOfBookies, BookKeeper.DigestType.MAC, - new byte[0]); - bk.deleteLedger(lh.ledgerId); - bk.close(); - } - - @Test - public void testNukeExistingClusterWithForceOption() throws Exception { - String ledgersRootPath = "/testledgers"; - ServerConfiguration newConfig = new ServerConfiguration(baseConf); - newConfig.setMetadataServiceUri(newMetadataServiceUri(ledgersRootPath)); - List bookiesRegPaths = new ArrayList(); - initiateNewClusterAndCreateLedgers(newConfig, bookiesRegPaths); - - /* - * before nuking existing cluster, bookies shouldn't be registered - * anymore - */ - for (int i = 0; i < bookiesRegPaths.size(); i++) { - zkc.delete(bookiesRegPaths.get(i), -1); - } - - Assert.assertTrue("New cluster should be nuked successfully", - BookKeeperAdmin.nukeExistingCluster(newConfig, ledgersRootPath, null, true)); - Assert.assertTrue("Cluster rootpath should have been deleted successfully " + ledgersRootPath, - (zkc.exists(ledgersRootPath, false) == null)); - } - - @Test - public void testNukeExistingClusterWithInstanceId() throws Exception { - String ledgersRootPath = "/testledgers"; - ServerConfiguration newConfig = new ServerConfiguration(baseConf); - newConfig.setMetadataServiceUri(newMetadataServiceUri(ledgersRootPath)); - List bookiesRegPaths = new ArrayList(); - initiateNewClusterAndCreateLedgers(newConfig, bookiesRegPaths); - - /* - * before nuking existing cluster, bookies shouldn't be registered - * anymore - */ - for (int i = 0; i < bookiesRegPaths.size(); i++) { - zkc.delete(bookiesRegPaths.get(i), -1); - } - - byte[] data = zkc.getData( - ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) + "/" + BookKeeperConstants.INSTANCEID, - false, null); - String readInstanceId = new String(data, UTF_8); - - Assert.assertTrue("New cluster should be nuked successfully", - BookKeeperAdmin.nukeExistingCluster(newConfig, ledgersRootPath, readInstanceId, false)); - Assert.assertTrue("Cluster rootpath should have been deleted successfully " + ledgersRootPath, - (zkc.exists(ledgersRootPath, false) == null)); - } - - @Test - public void tryNukingExistingClustersWithInvalidParams() throws Exception { - String ledgersRootPath = "/testledgers"; - ServerConfiguration newConfig = new ServerConfiguration(baseConf); - newConfig.setMetadataServiceUri(newMetadataServiceUri(ledgersRootPath)); - List bookiesRegPaths = new ArrayList(); - initiateNewClusterAndCreateLedgers(newConfig, bookiesRegPaths); - - /* - * create ledger with a specific ledgerid - */ - BookKeeper bk = new BookKeeper(new ClientConfiguration(newConfig)); - long ledgerId = 23456789L; - LedgerHandle lh = bk.createLedgerAdv(ledgerId, 1, 1, 1, BookKeeper.DigestType.MAC, new byte[0], null); - lh.close(); - - /* - * read instanceId - */ - byte[] data = zkc.getData( - ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) + "/" + BookKeeperConstants.INSTANCEID, - false, null); - String readInstanceId = new String(data, UTF_8); - - /* - * register a RO bookie - */ - String ipString = InetAddresses.fromInteger((new Random()).nextInt()).getHostAddress(); - String roBookieRegPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) - + "/" + AVAILABLE_NODE + "/" + READONLY + "/" + ipString + ":3181"; - zkc.create(roBookieRegPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); - - Assert.assertFalse("Cluster should'nt be nuked since instanceid is not provided and force option is not set", - BookKeeperAdmin.nukeExistingCluster(newConfig, ledgersRootPath, null, false)); - Assert.assertFalse("Cluster should'nt be nuked since incorrect instanceid is provided", - BookKeeperAdmin.nukeExistingCluster(newConfig, ledgersRootPath, "incorrectinstanceid", false)); - Assert.assertFalse("Cluster should'nt be nuked since bookies are still registered", - BookKeeperAdmin.nukeExistingCluster(newConfig, ledgersRootPath, readInstanceId, false)); - /* - * delete all rw bookies registration - */ - for (int i = 0; i < bookiesRegPaths.size(); i++) { - zkc.delete(bookiesRegPaths.get(i), -1); - } - Assert.assertFalse("Cluster should'nt be nuked since ro bookie is still registered", - BookKeeperAdmin.nukeExistingCluster(newConfig, ledgersRootPath, readInstanceId, false)); - - /* - * make sure no node is deleted - */ - Assert.assertTrue("Cluster rootpath should be existing " + ledgersRootPath, - (zkc.exists(ledgersRootPath, false) != null)); - String availableBookiesPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) + "/" + AVAILABLE_NODE; - Assert.assertTrue("AvailableBookiesPath should be existing " + availableBookiesPath, - (zkc.exists(availableBookiesPath, false) != null)); - String instanceIdPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) - + "/" + BookKeeperConstants.INSTANCEID; - Assert.assertTrue("InstanceId node should be existing" + instanceIdPath, - (zkc.exists(instanceIdPath, false) != null)); - String ledgersLayout = ledgersRootPath + "/" + BookKeeperConstants.LAYOUT_ZNODE; - Assert.assertTrue("Layout node should be existing" + ledgersLayout, (zkc.exists(ledgersLayout, false) != null)); - - /* - * ledger should not be deleted. - */ - lh = bk.openLedgerNoRecovery(ledgerId, BookKeeper.DigestType.MAC, new byte[0]); - lh.close(); - bk.close(); - - /* - * delete ro bookie reg znode - */ - zkc.delete(roBookieRegPath, -1); - - Assert.assertTrue("Cluster should be nuked since no bookie is registered", - BookKeeperAdmin.nukeExistingCluster(newConfig, ledgersRootPath, readInstanceId, false)); - Assert.assertTrue("Cluster rootpath should have been deleted successfully " + ledgersRootPath, - (zkc.exists(ledgersRootPath, false) == null)); - } - - void initiateNewClusterAndCreateLedgers(ServerConfiguration newConfig, List bookiesRegPaths) - throws Exception { - Assert.assertTrue("New cluster should be initialized successfully", BookKeeperAdmin.initNewCluster(newConfig)); - - /** - * create znodes simulating existence of Bookies in the cluster - */ - int numberOfBookies = 3; - Random rand = new Random(); - for (int i = 0; i < numberOfBookies; i++) { - String ipString = InetAddresses.fromInteger(rand.nextInt()).getHostAddress(); - bookiesRegPaths.add(ZKMetadataDriverBase.resolveZkLedgersRootPath(newConfig) - + "/" + AVAILABLE_NODE + "/" + ipString + ":3181"); - zkc.create(bookiesRegPaths.get(i), new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); - } - - /* - * now it should be possible to create ledger and delete the same - */ - BookKeeper bk = new BookKeeper(new ClientConfiguration(newConfig)); - LedgerHandle lh; - int numOfLedgers = 5; - for (int i = 0; i < numOfLedgers; i++) { - lh = bk.createLedger(numberOfBookies, numberOfBookies, numberOfBookies, BookKeeper.DigestType.MAC, - new byte[0]); - lh.close(); - } - bk.close(); - } - - @Test - public void testGetListOfEntriesOfClosedLedger() throws Exception { - testGetListOfEntriesOfLedger(true); - } - - @Test - public void testGetListOfEntriesOfNotClosedLedger() throws Exception { - testGetListOfEntriesOfLedger(false); - } - - @Test - public void testGetListOfEntriesOfNonExistingLedger() throws Exception { - long nonExistingLedgerId = 56789L; - - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - for (int i = 0; i < bookieCount(); i++) { - CompletableFuture futureResult = bkAdmin - .asyncGetListOfEntriesOfLedger(addressByIndex(i), nonExistingLedgerId); - try { - futureResult.get(); - fail("asyncGetListOfEntriesOfLedger is supposed to be failed with NoSuchLedgerExistsException"); - } catch (ExecutionException ee) { - assertTrue(ee.getCause() instanceof BKException); - BKException e = (BKException) ee.getCause(); - assertEquals(e.getCode(), BKException.Code.NoSuchLedgerExistsException); - } - } - } - } - - public void testGetListOfEntriesOfLedger(boolean isLedgerClosed) throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numOfEntries = 6; - BookKeeper bkc = new BookKeeper(conf); - LedgerHandle lh = bkc.createLedger(numOfBookies, numOfBookies, digestType, "testPasswd".getBytes()); - long lId = lh.getId(); - for (int i = 0; i < numOfEntries; i++) { - lh.addEntry("000".getBytes()); - } - if (isLedgerClosed) { - lh.close(); - } - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - for (int i = 0; i < bookieCount(); i++) { - CompletableFuture futureResult = bkAdmin - .asyncGetListOfEntriesOfLedger(addressByIndex(i), lId); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = futureResult.get(); - assertEquals("Number of entries", numOfEntries, - availabilityOfEntriesOfLedger.getTotalNumOfAvailableEntries()); - for (int j = 0; j < numOfEntries; j++) { - assertTrue("Entry should be available: " + j, availabilityOfEntriesOfLedger.isEntryAvailable(j)); - } - assertFalse("Entry should not be available: " + numOfEntries, - availabilityOfEntriesOfLedger.isEntryAvailable(numOfEntries)); - } - } - bkc.close(); - } - - @Test - public void testGetEntriesFromEmptyLedger() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - LedgerHandle lh = bkc.createLedger(numOfBookies, numOfBookies, digestType, "testPasswd".getBytes(UTF_8)); - lh.close(); - long ledgerId = lh.getId(); - - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - Iterator iter = bkAdmin.readEntries(ledgerId, 0, 0).iterator(); - assertFalse(iter.hasNext()); - } - - bkc.close(); - } - - @Test - public void testGetListOfEntriesOfLedgerWithJustOneBookieInWriteQuorum() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numOfEntries = 6; - BookKeeper bkc = new BookKeeper(conf); - /* - * in this testsuite there are going to be 2 (numOfBookies) and if - * writeQuorum is 1 then it will stripe entries to those two bookies. - */ - LedgerHandle lh = bkc.createLedger(2, 1, digestType, "testPasswd".getBytes()); - long lId = lh.getId(); - for (int i = 0; i < numOfEntries; i++) { - lh.addEntry("000".getBytes()); - } - - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - for (int i = 0; i < bookieCount(); i++) { - CompletableFuture futureResult = bkAdmin - .asyncGetListOfEntriesOfLedger(addressByIndex(i), lId); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = futureResult.get(); - /* - * since num of bookies in the ensemble is 2 and - * writeQuorum/ackQuorum is 1, it will stripe to these two - * bookies and hence in each bookie there will be only - * numOfEntries/2 entries. - */ - assertEquals("Number of entries", numOfEntries / 2, - availabilityOfEntriesOfLedger.getTotalNumOfAvailableEntries()); - } - } - bkc.close(); - } - - @Test - public void testGetBookies() throws Exception { - String ledgersRootPath = "/ledgers"; - Assert.assertTrue("Cluster rootpath should have been created successfully " + ledgersRootPath, - (zkc.exists(ledgersRootPath, false) != null)); - String bookieCookiePath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf) - + "/" + BookKeeperConstants.COOKIE_NODE; - Assert.assertTrue("AvailableBookiesPath should have been created successfully " + bookieCookiePath, - (zkc.exists(bookieCookiePath, false) != null)); - - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - Collection availableBookies = bkAdmin.getAvailableBookies(); - Assert.assertEquals(availableBookies.size(), bookieCount()); - - for (int i = 0; i < bookieCount(); i++) { - availableBookies.contains(addressByIndex(i)); - } - - BookieServer killedBookie = serverByIndex(1); - killBookieAndWaitForZK(1); - - Collection remainingBookies = bkAdmin.getAvailableBookies(); - Assert.assertFalse(remainingBookies.contains(killedBookie)); - - Collection allBookies = bkAdmin.getAllBookies(); - for (int i = 0; i < bookieCount(); i++) { - remainingBookies.contains(addressByIndex(i)); - allBookies.contains(addressByIndex(i)); - } - - Assert.assertEquals(remainingBookies.size(), allBookies.size() - 1); - Assert.assertTrue(allBookies.contains(killedBookie.getBookieId())); - } - } - - @Test - public void testGetListOfEntriesOfLedgerWithEntriesNotStripedToABookie() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - /* - * in this testsuite there are going to be 2 (numOfBookies) bookies and - * we are having ensemble of size 2. - */ - LedgerHandle lh = bkc.createLedger(2, 1, digestType, "testPasswd".getBytes()); - long lId = lh.getId(); - /* - * ledger is writeclosed without adding any entry. - */ - lh.close(); - CountDownLatch callbackCalled = new CountDownLatch(1); - AtomicBoolean exceptionInCallback = new AtomicBoolean(false); - AtomicInteger exceptionCode = new AtomicInteger(BKException.Code.OK); - BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString()); - /* - * since no entry is added, callback is supposed to fail with - * NoSuchLedgerExistsException. - */ - bkAdmin.asyncGetListOfEntriesOfLedger(addressByIndex(0), lId) - .whenComplete((availabilityOfEntriesOfLedger, throwable) -> { - exceptionInCallback.set(throwable != null); - if (throwable != null) { - exceptionCode.set(BKException.getExceptionCode(throwable)); - } - callbackCalled.countDown(); - }); - callbackCalled.await(); - assertTrue("Exception occurred", exceptionInCallback.get()); - assertEquals("Exception code", BKException.Code.NoSuchLedgerExistsException, exceptionCode.get()); - bkAdmin.close(); - bkc.close(); - } - - @Test - public void testAreEntriesOfLedgerStoredInTheBookieForLastEmptySegment() throws Exception { - int lastEntryId = 10; - long ledgerId = 100L; - BookieId bookie0 = new BookieSocketAddress("bookie0:3181").toBookieId(); - BookieId bookie1 = new BookieSocketAddress("bookie1:3181").toBookieId(); - BookieId bookie2 = new BookieSocketAddress("bookie2:3181").toBookieId(); - BookieId bookie3 = new BookieSocketAddress("bookie3:3181").toBookieId(); - - List ensembleOfSegment1 = new ArrayList(); - ensembleOfSegment1.add(bookie0); - ensembleOfSegment1.add(bookie1); - ensembleOfSegment1.add(bookie2); - - List ensembleOfSegment2 = new ArrayList(); - ensembleOfSegment2.add(bookie3); - ensembleOfSegment2.add(bookie1); - ensembleOfSegment2.add(bookie2); - - LedgerMetadataBuilder builder = LedgerMetadataBuilder.create(); - builder.withId(ledgerId) - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(2) - .withDigestType(digestType.toApiDigestType()) - .withPassword(PASSWORD.getBytes()) - .newEnsembleEntry(0, ensembleOfSegment1) - .newEnsembleEntry(lastEntryId + 1, ensembleOfSegment2) - .withLastEntryId(lastEntryId).withLength(65576).withClosedState(); - LedgerMetadata meta = builder.build(); - - assertFalse("expected areEntriesOfLedgerStoredInTheBookie to return False for bookie3", - BookKeeperAdmin.areEntriesOfLedgerStoredInTheBookie(ledgerId, bookie3, meta)); - assertTrue("expected areEntriesOfLedgerStoredInTheBookie to return true for bookie2", - BookKeeperAdmin.areEntriesOfLedgerStoredInTheBookie(ledgerId, bookie2, meta)); - } - - @Test - public void testBookkeeperAdminFormatResetsLedgerIds() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - /* - * in this testsuite there are going to be 2 (numOfBookies) ledgers - * written and when formatting the BookieAdmin i expect that the - * ledger ids restart from 0 - */ - int numOfLedgers = 2; - try (BookKeeper bkc = new BookKeeper(conf)) { - Set ledgerIds = new HashSet<>(); - for (int n = 0; n < numOfLedgers; n++) { - try (LedgerHandle lh = bkc.createLedger(numOfBookies, numOfBookies, digestType, "L".getBytes())) { - ledgerIds.add(lh.getId()); - lh.addEntry("000".getBytes()); - } - } - - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - bkAdmin.format(baseConf, false, true); - } - - /** - * ledgers created after format produce the same ids - */ - for (int n = 0; n < numOfLedgers; n++) { - try (LedgerHandle lh = bkc.createLedger(numOfBookies, numOfBookies, digestType, "L".getBytes())) { - lh.addEntry("000".getBytes()); - assertTrue(ledgerIds.contains(lh.getId())); - } - } - } - } - - private void testBookieServiceInfo(boolean readonly, boolean legacy) throws Exception { - File tmpDir = tmpDirs.createNew("bookie", "test"); - final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[]{tmpDir.getPath()}) - .setBookiePort(PortManager.nextFreePort()) - .setMetadataServiceUri(metadataServiceUri); - - LifecycleComponent server = Main.buildBookieServer(new BookieConfiguration(conf)); - // 2. start the server - CompletableFuture stackComponentFuture = ComponentStarter.startComponent(server); - while (server.lifecycleState() != Lifecycle.State.STARTED) { - Thread.sleep(100); - } - - ServerConfiguration bkConf = newServerConfiguration().setForceReadOnlyBookie(readonly); - BookieServer bkServer = startBookie(bkConf).getServer(); - - BookieId bookieId = bkServer.getBookieId(); - String host = bkServer.getLocalAddress().getHostName(); - int port = bkServer.getLocalAddress().getPort(); - - if (legacy) { - String regPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(bkConf) + "/" + AVAILABLE_NODE; - regPath = readonly - ? regPath + READONLY + "/" + bookieId - : regPath + "/" + bookieId.toString(); - // deleting the metadata, so that the bookie registration should - // continue successfully with legacy BookieServiceInfo - zkc.setData(regPath, new byte[]{}, -1); - } - - try (BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString())) { - BookieServiceInfo bookieServiceInfo = bkAdmin.getBookieServiceInfo(bookieId); - - assertThat(bookieServiceInfo.getEndpoints().size(), is(1)); - BookieServiceInfo.Endpoint endpoint = bookieServiceInfo.getEndpoints().stream() - .filter(e -> Objects.equals(e.getId(), bookieId.getId())) - .findFirst() - .get(); - assertNotNull("Endpoint " + bookieId + " not found.", endpoint); - - assertThat(endpoint.getHost(), is(host)); - assertThat(endpoint.getPort(), is(port)); - assertThat(endpoint.getProtocol(), is("bookie-rpc")); - } - - bkServer.shutdown(); - stackComponentFuture.cancel(true); - } - - @Test - public void testBookieServiceInfoWritable() throws Exception { - testBookieServiceInfo(false, false); - } - - @Test - public void testBookieServiceInfoReadonly() throws Exception { - testBookieServiceInfo(true, false); - } - - @Test - public void testLegacyBookieServiceInfo() throws Exception { - testBookieServiceInfo(false, true); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientTestsWithBookieErrors.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientTestsWithBookieErrors.java deleted file mode 100644 index 373e4f523c8..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientTestsWithBookieErrors.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.function.Consumer; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.SortedLedgerStorage; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the bookkeeper client with errors from Bookies. - */ -public class BookKeeperClientTestsWithBookieErrors extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(BookKeeperClientTestsWithBookieErrors.class); - private static final int NUM_BOOKIES = 3; - // The amount of sleeptime to sleep in injectSleepWhileRead fault injection - private final long sleepTime; - // Fault injection which would sleep for sleepTime before returning readEntry call - private final Consumer injectSleepWhileRead; - // Fault injection which would corrupt the entry data before returning readEntry call - private final Consumer injectCorruptData; - /* - * The ordered list of injections for the Bookies (LedgerStorage). The first - * bookie to get readEntry call will use the first faultInjection, and the - * second bookie to get readentry call will use the second one and so on.. - * - * It is assumed that there would be faultInjection for each Bookie. So if - * there aren't NUM_BOOKIES num of faulInjections in this list then it will - * fail with NullPointerException - */ - private static List> faultInjections = new ArrayList>(); - /* - * This map is used for storing LedgerStorage and the corresponding - * faultInjection, according to the faultInjections list - */ - private static HashMap> storageFaultInjectionsMap = - new HashMap>(); - // Lock object for synchronizing injectCorruptData and faultInjections - private static final Object lock = new Object(); - - public BookKeeperClientTestsWithBookieErrors() { - super(NUM_BOOKIES); - baseConf.setLedgerStorageClass(MockSortedLedgerStorage.class.getName()); - - // this fault injection will corrupt the entry data by modifying the last byte of the entry - injectCorruptData = (byteBuf) -> { - ByteBuffer buf = byteBuf.nioBuffer(); - int lastByteIndex = buf.limit() - 1; - buf.put(lastByteIndex, (byte) (buf.get(lastByteIndex) - 1)); - }; - - // this fault injection, will sleep for ReadEntryTimeout+2 secs before returning the readEntry call - sleepTime = (baseClientConf.getReadEntryTimeout() + 2) * 1000; - injectSleepWhileRead = (byteBuf) -> { - try { - Thread.sleep(sleepTime); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - }; - } - - @Before - public void setUp() throws Exception { - faultInjections.clear(); - storageFaultInjectionsMap.clear(); - super.setUp(); - } - - // Mock SortedLedgerStorage to simulate Fault Injection - static class MockSortedLedgerStorage extends SortedLedgerStorage { - public MockSortedLedgerStorage() { - super(); - } - - @Override - public ByteBuf getEntry(long ledgerId, long entryId) throws IOException, BookieException { - Consumer faultInjection; - synchronized (lock) { - faultInjection = storageFaultInjectionsMap.get(this); - if (faultInjection == null) { - int readLedgerStorageIndex = storageFaultInjectionsMap.size(); - faultInjection = faultInjections.get(readLedgerStorageIndex); - storageFaultInjectionsMap.put(this, faultInjection); - } - } - ByteBuf byteBuf = super.getEntry(ledgerId, entryId); - faultInjection.accept(byteBuf); - return byteBuf; - } - } - - // In this testcase all the bookies will return corrupt entry - @Test(timeout = 60000) - public void testBookkeeperAllDigestErrors() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] passwd = "AAAAAAA".getBytes(); - - // all the bookies need to return corrupt data - faultInjections.add(injectCorruptData); - faultInjections.add(injectCorruptData); - faultInjections.add(injectCorruptData); - - LedgerHandle wlh = bkc.createLedger(3, 3, 2, DigestType.CRC32, passwd); - long id = wlh.getId(); - for (int i = 0; i < 10; i++) { - wlh.addEntry("foobarfoo".getBytes()); - } - wlh.close(); - - LedgerHandle rlh = bkc.openLedger(id, DigestType.CRC32, passwd); - try { - rlh.readEntries(4, 4); - fail("It is expected to fail with BKDigestMatchException"); - } catch (BKException.BKDigestMatchException e) { - } - rlh.close(); - bkc.close(); - } - - // In this testcase first two bookies will sleep (for ReadEntryTimeout+2 secs) before returning the data, - // and the last one will return corrupt data - @Test(timeout = 60000) - public void testBKReadFirstTimeoutThenDigestError() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] passwd = "AAAAAAA".getBytes(); - - faultInjections.add(injectSleepWhileRead); - faultInjections.add(injectSleepWhileRead); - faultInjections.add(injectCorruptData); - - LedgerHandle wlh = bkc.createLedger(3, 3, 2, DigestType.CRC32, passwd); - long id = wlh.getId(); - for (int i = 0; i < 10; i++) { - wlh.addEntry("foobarfoo".getBytes()); - } - wlh.close(); - - LedgerHandle rlh = bkc.openLedger(id, DigestType.CRC32, passwd); - try { - rlh.readEntries(4, 4); - fail("It is expected to fail with BKDigestMatchException"); - } catch (BKException.BKDigestMatchException e) { - } - rlh.close(); - bkc.close(); - } - - // In this testcase first one will return corrupt data and the last two bookies will - // sleep (for ReadEntryTimeout+2 secs) before returning the data - @Test(timeout = 60000) - public void testBKReadFirstDigestErrorThenTimeout() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] passwd = "AAAAAAA".getBytes(); - - faultInjections.add(injectCorruptData); - faultInjections.add(injectSleepWhileRead); - faultInjections.add(injectSleepWhileRead); - - LedgerHandle wlh = bkc.createLedger(3, 3, 2, DigestType.CRC32, passwd); - long id = wlh.getId(); - for (int i = 0; i < 10; i++) { - wlh.addEntry("foobarfoo".getBytes()); - } - wlh.close(); - - LedgerHandle rlh = bkc.openLedger(id, DigestType.CRC32, passwd); - try { - rlh.readEntries(4, 4); - fail("It is expected to fail with BKDigestMatchException"); - } catch (BKException.BKDigestMatchException e) { - } - rlh.close(); - bkc.close(); - } - - // In this testcase first two bookies are killed before making the readentry call - // and the last one will return corrupt data - @Test(timeout = 60000) - public void testBKReadFirstBookiesDownThenDigestError() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] passwd = "AAAAAAA".getBytes(); - - faultInjections.add(injectCorruptData); - - LedgerHandle wlh = bkc.createLedger(3, 3, 2, DigestType.CRC32, passwd); - long id = wlh.getId(); - wlh.addEntry("foobarfoo".getBytes()); - wlh.close(); - - super.killBookie(0); - super.killBookie(1); - - Thread.sleep(500); - - LedgerHandle rlh = bkc.openLedger(id, DigestType.CRC32, passwd); - try { - rlh.readEntries(0, 0); - fail("It is expected to fail with BKDigestMatchException"); - } catch (BKException.BKDigestMatchException e) { - } - rlh.close(); - bkc.close(); - } - - // In this testcase all the bookies will sleep (for ReadEntryTimeout+2 secs) before returning the data - @Test(timeout = 60000) - public void testBKReadAllTimeouts() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] passwd = "AAAAAAA".getBytes(); - - faultInjections.add(injectSleepWhileRead); - faultInjections.add(injectSleepWhileRead); - faultInjections.add(injectSleepWhileRead); - - LedgerHandle wlh = bkc.createLedger(3, 3, 2, DigestType.CRC32, passwd); - long id = wlh.getId(); - for (int i = 0; i < 10; i++) { - wlh.addEntry("foobarfoo".getBytes()); - } - wlh.close(); - - LedgerHandle rlh = bkc.openLedger(id, DigestType.CRC32, passwd); - try { - rlh.readEntries(4, 4); - fail("It is expected to fail with BKTimeoutException"); - } catch (BKException.BKTimeoutException e) { - } - rlh.close(); - bkc.close(); - } - - // In this testcase first two bookies will sleep (for ReadEntryTimeout+2 secs) before returning the data, - // but the last one will return as expected - @Test(timeout = 60000) - public void testBKReadTwoBookiesTimeout() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] passwd = "AAAAAAA".getBytes(); - - faultInjections.add(injectSleepWhileRead); - faultInjections.add(injectSleepWhileRead); - faultInjections.add((byteBuf) -> { - }); - - LedgerHandle wlh = bkc.createLedger(3, 3, 2, DigestType.CRC32, passwd); - long id = wlh.getId(); - for (int i = 0; i < 10; i++) { - wlh.addEntry("foobarfoo".getBytes()); - } - wlh.close(); - - LedgerHandle rlh = bkc.openLedger(id, DigestType.CRC32, passwd); - LedgerEntry entry = rlh.readEntries(4, 4).nextElement(); - Assert.assertTrue("The read Entry should match with what have been written", - (new String(entry.getEntry())).equals("foobarfoo")); - rlh.close(); - bkc.close(); - } - - // In this testcase first two bookies return the corrupt data, - // but the last one will return as expected - @Test(timeout = 60000) - public void testBKReadTwoBookiesWithDigestError() throws Exception { - ClientConfiguration conf = new ClientConfiguration() - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] passwd = "AAAAAAA".getBytes(); - - faultInjections.add(injectCorruptData); - faultInjections.add(injectCorruptData); - faultInjections.add((byteBuf) -> { - }); - - LedgerHandle wlh = bkc.createLedger(3, 3, 2, DigestType.CRC32, passwd); - long id = wlh.getId(); - for (int i = 0; i < 10; i++) { - wlh.addEntry("foobarfoo".getBytes()); - } - wlh.close(); - - LedgerHandle rlh = bkc.openLedger(id, DigestType.CRC32, passwd); - LedgerEntry entry = rlh.readEntries(4, 4).nextElement(); - Assert.assertTrue("The read Entry should match with what have been written", - (new String(entry.getEntry())).equals("foobarfoo")); - rlh.close(); - bkc.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientZKSessionExpiry.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientZKSessionExpiry.java deleted file mode 100644 index b1a8bb66dd7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientZKSessionExpiry.java +++ /dev/null @@ -1,83 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF 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. -* -*/ -package org.apache.bookkeeper.client; - -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestCallbacks.AddCallbackFuture; -import org.apache.bookkeeper.zookeeper.ZooKeeperWatcherBase; -import org.apache.zookeeper.ZooKeeper; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the bookkeeper client while losing a ZK session. - */ -public class BookKeeperClientZKSessionExpiry extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(BookKeeperClientZKSessionExpiry.class); - - public BookKeeperClientZKSessionExpiry() { - super(4); - } - - @Test - public void testSessionLossWhileWriting() throws Exception { - - Thread expiryThread = new Thread() { - @Override - public void run() { - try { - while (true) { - Thread.sleep(5000); - long sessionId = bkc.getZkHandle().getSessionId(); - byte[] sessionPasswd = bkc.getZkHandle().getSessionPasswd(); - - try { - ZooKeeperWatcherBase watcher = new ZooKeeperWatcherBase(10000); - ZooKeeper zk = new ZooKeeper(zkUtil.getZooKeeperConnectString(), 10000, - watcher, sessionId, sessionPasswd); - zk.close(); - } catch (Exception e) { - LOG.info("Error killing session", e); - } - } - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - return; - } - } - }; - expiryThread.start(); - - for (int i = 0; i < 3; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, 2, BookKeeper.DigestType.MAC, "foobar".getBytes()); - for (int j = 0; j < 100; j++) { - lh.asyncAddEntry("foobar".getBytes(), new AddCallbackFuture(j), null); - } - startNewBookie(); - killBookie(0); - - lh.addEntry("lastEntry".getBytes()); - - lh.close(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperCloseTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperCloseTest.java deleted file mode 100644 index 2dd5e544418..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperCloseTest.java +++ /dev/null @@ -1,612 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.util.concurrent.SettableFuture; -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.util.Enumeration; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.CloseCallback; -import org.apache.bookkeeper.client.AsyncCallback.CreateCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BKException.BKClientClosedException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This unit test verifies the behavior of bookkeeper apis, where the operations - * are being executed through a closed bookkeeper client. - */ -public class BookKeeperCloseTest extends BookKeeperClusterTestCase { - - // Depending on the taste, select the amount of logging - // by decommenting one of the two lines below - // static Logger LOG = Logger.getRootLogger(); - private static final Logger LOG = LoggerFactory - .getLogger(BookKeeperCloseTest.class); - private DigestType digestType = DigestType.CRC32; - private static final String PASSWORD = "testPasswd"; - private static final BiConsumer NOOP_BICONSUMER = (l, e) -> { }; - - public BookKeeperCloseTest() { - super(3); - } - - private void restartBookieSlow() throws Exception{ - ServerConfiguration conf = killBookie(0); - - Bookie delayBookie = new TestBookieImpl(conf) { - @Override - public void recoveryAddEntry(ByteBuf entry, WriteCallback cb, - Object ctx, byte[] masterKey) - throws IOException, BookieException, InterruptedException { - try { - Thread.sleep(5000); - } catch (InterruptedException ie) { - // ignore, only interrupted if shutting down, - // and an exception would spam the logs - Thread.currentThread().interrupt(); - } - super.recoveryAddEntry(entry, cb, ctx, masterKey); - } - - @Override - public void addEntry(ByteBuf entry, boolean ackBeforeSync, WriteCallback cb, - Object ctx, byte[] masterKey) - throws IOException, BookieException, InterruptedException { - try { - Thread.sleep(5000); - } catch (InterruptedException ie) { - // ignore, only interrupted if shutting down, - // and an exception would spam the logs - Thread.currentThread().interrupt(); - } - super.addEntry(entry, ackBeforeSync, cb, ctx, masterKey); - } - - @Override - public ByteBuf readEntry(long ledgerId, long entryId) - throws IOException, NoLedgerException, BookieException { - try { - Thread.sleep(5000); - } catch (InterruptedException ie) { - // ignore, only interrupted if shutting down, - // and an exception would spam the logs - Thread.currentThread().interrupt(); - } - return super.readEntry(ledgerId, entryId); - } - }; - startAndAddBookie(conf, delayBookie); - } - - /** - * Test that createledger using bookkeeper client which is closed should - * throw ClientClosedException. - */ - @Test - public void testCreateLedger() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Closing bookkeeper client"); - bk.close(); - try { - bk.createLedger(digestType, PASSWORD.getBytes()); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - - // using async, because this could trigger an assertion - final AtomicInteger returnCode = new AtomicInteger(0); - final CountDownLatch openLatch = new CountDownLatch(1); - CreateCallback cb = new CreateCallback() { - @Override - public void createComplete(int rc, LedgerHandle lh, Object ctx) { - returnCode.set(rc); - openLatch.countDown(); - } - }; - bk.asyncCreateLedger(3, 2, digestType, PASSWORD.getBytes(), cb, - openLatch); - - LOG.info("Waiting to finish the ledger creation"); - // wait for creating the ledger - assertTrue("create ledger call should have completed", - openLatch.await(20, TimeUnit.SECONDS)); - assertEquals("Succesfully created ledger through closed bkclient!", - BKException.Code.ClientClosedException, returnCode.get()); - } - - /** - * Test that opening a ledger using bookkeeper client which is closed should - * throw ClientClosedException. - */ - @Test - public void testFenceLedger() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh = createLedgerWithEntries(bk, 100); - LOG.info("Closing bookkeeper client"); - - restartBookieSlow(); - - bk.close(); - - try { - bk.openLedger(lh.getId(), digestType, PASSWORD.getBytes()); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - - try { - bk.openLedgerNoRecovery(lh.getId(), digestType, PASSWORD.getBytes()); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - - final AtomicInteger returnCode = new AtomicInteger(0); - final CountDownLatch openLatch = new CountDownLatch(1); - AsyncCallback.OpenCallback cb = new AsyncCallback.OpenCallback() { - public void openComplete(int rc, LedgerHandle lh, Object ctx) { - returnCode.set(rc); - openLatch.countDown(); - } - }; - bk.asyncOpenLedger(lh.getId(), digestType, PASSWORD.getBytes(), cb, - openLatch); - - LOG.info("Waiting to open the ledger asynchronously"); - assertTrue("Open call should have completed", - openLatch.await(20, TimeUnit.SECONDS)); - assertTrue("Open should not have succeeded through closed bkclient!", - BKException.Code.ClientClosedException == returnCode.get()); - } - - /** - * Test that deleting a ledger using bookkeeper client which is closed - * should throw ClientClosedException. - */ - @Test - public void testDeleteLedger() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh = createLedgerWithEntries(bk, 100); - LOG.info("Closing bookkeeper client"); - bk.close(); - try { - bk.deleteLedger(lh.getId()); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - - // using async, because this could trigger an assertion - final AtomicInteger returnCode = new AtomicInteger(0); - final CountDownLatch openLatch = new CountDownLatch(1); - AsyncCallback.DeleteCallback cb = new AsyncCallback.DeleteCallback() { - public void deleteComplete(int rc, Object ctx) { - returnCode.set(rc); - openLatch.countDown(); - } - }; - bk.asyncDeleteLedger(lh.getId(), cb, openLatch); - - LOG.info("Waiting to delete the ledger asynchronously"); - assertTrue("Delete call should have completed", - openLatch.await(20, TimeUnit.SECONDS)); - assertEquals("Delete should not have succeeded through closed bkclient!", - BKException.Code.ClientClosedException, returnCode.get()); - } - - /** - * Test that adding entry to a ledger using bookkeeper client which is - * closed should throw ClientClosedException. - */ - @Test - public void testAddLedgerEntry() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh = createLedgerWithEntries(bk, 1); - LOG.info("Closing bookkeeper client"); - - restartBookieSlow(); - - bk.close(); - - try { - lh.addEntry("foobar".getBytes()); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - - final CountDownLatch completeLatch = new CountDownLatch(1); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - lh.asyncAddEntry("foobar".getBytes(), new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, - Object ctx) { - rc.set(rccb); - completeLatch.countDown(); - } - }, null); - - LOG.info("Waiting to finish adding another entry asynchronously"); - assertTrue("Add entry to ledger call should have completed", - completeLatch.await(20, TimeUnit.SECONDS)); - assertEquals( - "Add entry to ledger should not have succeeded through closed bkclient!", - BKException.Code.ClientClosedException, rc.get()); - } - - /** - * Test that closing a ledger using bookkeeper client which is closed should - * throw ClientClosedException. - */ - @Test - public void testCloseLedger() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh = createLedgerWithEntries(bk, 100); - LedgerHandle lh2 = createLedgerWithEntries(bk, 100); - - LOG.info("Closing bookkeeper client"); - bk.close(); - - try { - lh.close(); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - - final CountDownLatch completeLatch = new CountDownLatch(1); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - lh2.asyncClose(new CloseCallback() { - public void closeComplete(int rccb, LedgerHandle lh, Object ctx) { - rc.set(rccb); - completeLatch.countDown(); - } - }, null); - - LOG.info("Waiting to finish adding another entry asynchronously"); - assertTrue("Close ledger call should have completed", - completeLatch.await(20, TimeUnit.SECONDS)); - assertEquals( - "Close ledger should have succeeded through closed bkclient!", - BKException.Code.ClientClosedException, rc.get()); - } - - /** - * Test that reading entry from a ledger using bookkeeper client which is - * closed should throw ClientClosedException. - */ - @Test - public void testReadLedgerEntry() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - int numOfEntries = 100; - LedgerHandle lh = createLedgerWithEntries(bk, numOfEntries); - LOG.info("Closing bookkeeper client"); - - restartBookieSlow(); - - bk.close(); - - try { - lh.readEntries(0, numOfEntries - 1); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - - final CountDownLatch readLatch = new CountDownLatch(1); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - ReadCallback cb = new ReadCallback() { - @Override - public void readComplete(int rccb, LedgerHandle lh, - Enumeration seq, Object ctx) { - rc.set(rccb); - readLatch.countDown(); - } - }; - lh.asyncReadEntries(0, numOfEntries - 1, cb, readLatch); - - LOG.info("Waiting to finish reading the entries asynchronously"); - assertTrue("Read entry ledger call should have completed", - readLatch.await(20, TimeUnit.SECONDS)); - assertEquals( - "Read entry ledger should have succeeded through closed bkclient!", - BKException.Code.ClientClosedException, rc.get()); - } - - /** - * Test that readlastconfirmed entry from a ledger using bookkeeper client - * which is closed should throw ClientClosedException. - */ - @Test - public void testReadLastConfirmed() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh = createLedgerWithEntries(bk, 100); - LOG.info("Closing bookkeeper client"); - - // make all bookies slow - restartBookieSlow(); - restartBookieSlow(); - restartBookieSlow(); - - bk.close(); - - final CountDownLatch readLatch = new CountDownLatch(1); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - AsyncCallback.ReadLastConfirmedCallback cb = new AsyncCallback.ReadLastConfirmedCallback() { - - @Override - public void readLastConfirmedComplete(int rccb, long lastConfirmed, - Object ctx) { - rc.set(rccb); - readLatch.countDown(); - } - }; - lh.asyncReadLastConfirmed(cb, readLatch); - - LOG.info("Waiting to finish reading last confirmed entry asynchronously"); - assertTrue("ReadLastConfirmed call should have completed", - readLatch.await(20, TimeUnit.SECONDS)); - assertEquals( - "ReadLastConfirmed should have succeeded through closed bkclient!", - BKException.Code.ClientClosedException, rc.get()); - - try { - lh.readLastConfirmed(); - fail("should have failed, client is closed"); - } catch (BKClientClosedException e) { - // correct - } - } - - /** - * Test that checking a ledger using a closed BK client will - * throw a ClientClosedException. - */ - @Test - public void testLedgerCheck() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh = createLedgerWithEntries(bk, 100); - LOG.info("Closing bookkeeper client"); - LedgerChecker lc = new LedgerChecker(bk); - - restartBookieSlow(); - bk.close(); - - final CountDownLatch postLatch = new CountDownLatch(1); - final AtomicInteger postRc = new AtomicInteger(BKException.Code.OK); - lc.checkLedger(lh, new GenericCallback>() { - @Override - public void operationComplete(int rc, Set result) { - postRc.set(rc); - postLatch.countDown(); - } - }); - assertTrue("checkLedger should have finished", postLatch.await(30, TimeUnit.SECONDS)); - assertEquals("Should have client closed exception", - postRc.get(), BKException.Code.ClientClosedException); - } - - private static class CheckerCb implements GenericCallback> { - CountDownLatch latch = new CountDownLatch(1); - int rc = BKException.Code.OK; - Set result = null; - - @Override - public void operationComplete(int rc, Set result) { - this.rc = rc; - this.result = result; - latch.countDown(); - } - - int getRc(int time, TimeUnit unit) throws Exception { - if (latch.await(time, unit)) { - return rc; - } else { - throw new Exception("Didn't complete"); - } - } - - Set getResult(int time, TimeUnit unit) throws Exception { - if (latch.await(time, unit)) { - return result; - } else { - throw new Exception("Didn't complete"); - } - } - } - /** - * Test that BookKeeperAdmin operationg using a closed BK client will - * throw a ClientClosedException. - */ - @Test - public void testBookKeeperAdmin() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - try (BookKeeperAdmin bkadmin = new BookKeeperAdmin(bk, baseClientConf)) { - - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh1 = createLedgerWithEntries(bk, 100); - LedgerHandle lh2 = createLedgerWithEntries(bk, 100); - LedgerHandle lh3 = createLedgerWithEntries(bk, 100); - lh3.close(); - - BookieId bookieToKill = getBookie(0); - killBookie(bookieToKill); - startNewBookie(); - - CheckerCb checkercb = new CheckerCb(); - LedgerChecker lc = new LedgerChecker(bk); - lc.checkLedger(lh3, checkercb); - assertEquals("Should have completed", - checkercb.getRc(30, TimeUnit.SECONDS), BKException.Code.OK); - assertEquals("Should have a missing fragment", - 1, checkercb.getResult(30, TimeUnit.SECONDS).size()); - - // make sure a bookie in each quorum is slow - restartBookieSlow(); - restartBookieSlow(); - - bk.close(); - - try { - bkadmin.openLedger(lh1.getId()); - fail("Shouldn't be able to open with a closed client"); - } catch (BKException.BKClientClosedException cce) { - // correct behaviour - } - - try { - bkadmin.openLedgerNoRecovery(lh1.getId()); - fail("Shouldn't be able to open with a closed client"); - } catch (BKException.BKClientClosedException cce) { - // correct behaviour - } - - try { - bkadmin.recoverBookieData(bookieToKill); - fail("Shouldn't be able to recover with a closed client"); - } catch (BKException.BKClientClosedException cce) { - // correct behaviour - } - - try { - bkadmin.replicateLedgerFragment(lh3, - checkercb.getResult(10, TimeUnit.SECONDS).iterator().next(), NOOP_BICONSUMER); - fail("Shouldn't be able to replicate with a closed client"); - } catch (BKException.BKClientClosedException cce) { - // correct behaviour - } - } - } - - /** - * Test that the bookkeeper client doesn't leave any threads hanging around. - * See {@link https://issues.apache.org/jira/browse/BOOKKEEPER-804} - */ - @Test - public void testBookKeeperCloseThreads() throws Exception { - ThreadGroup group = new ThreadGroup("test-group"); - final SettableFuture future = SettableFuture.create(); - - Thread t = new Thread(group, "TestThread") { - @Override - public void run() { - try { - BookKeeper bk = new BookKeeper(baseClientConf); - // 9 is a ledger id of an existing ledger - LedgerHandle lh = bk.createLedger(BookKeeper.DigestType.CRC32, "passwd".getBytes()); - lh.addEntry("foobar".getBytes()); - lh.close(); - long id = lh.getId(); - // 9 is a ledger id of an existing ledger - lh = bk.openLedgerNoRecovery(id, BookKeeper.DigestType.CRC32, "passwd".getBytes()); - Enumeration entries = lh.readEntries(0, 0); - - lh.close(); - bk.close(); - future.set(null); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - future.setException(ie); - } catch (Exception e) { - future.setException(e); - } - } - }; - t.start(); - - future.get(); - t.join(); - - // check in a loop for 10 seconds - // because sometimes it takes a while to threads to go away - for (int i = 0; i < 10; i++) { - if (group.activeCount() > 0) { - Thread[] threads = new Thread[group.activeCount()]; - group.enumerate(threads); - for (Thread leftover : threads) { - LOG.error("Leftover thread after {} secs: {}", i, leftover); - } - Thread.sleep(1000); - } else { - break; - } - } - assertEquals("Should be no threads left in group", 0, group.activeCount()); - } - - private LedgerHandle createLedgerWithEntries(BookKeeper bk, int numOfEntries) - throws Exception { - LedgerHandle lh = bk - .createLedger(3, 3, digestType, PASSWORD.getBytes()); - - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - final CountDownLatch latch = new CountDownLatch(numOfEntries); - - final AddCallback cb = new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, - Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - latch.countDown(); - } - }; - for (int i = 0; i < numOfEntries; i++) { - lh.asyncAddEntry("foobar".getBytes(), cb, null); - } - if (!latch.await(30, TimeUnit.SECONDS)) { - throw new Exception("Entries took too long to add"); - } - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - return lh; - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java deleted file mode 100644 index 91612ec5c79..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java +++ /dev/null @@ -1,499 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF 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. -* -*/ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests of the main BookKeeper client. - */ -public class BookKeeperDiskSpaceWeightedLedgerPlacementTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(BookKeeperDiskSpaceWeightedLedgerPlacementTest.class); - private static final long MS_WEIGHT_UPDATE_TIMEOUT = 30000; - - public BookKeeperDiskSpaceWeightedLedgerPlacementTest() { - super(10); - } - - class BookKeeperCheckInfoReader extends BookKeeper { - BookKeeperCheckInfoReader(ClientConfiguration conf) throws BKException, IOException, InterruptedException { - super(conf); - } - - void blockUntilBookieWeightIs(BookieId bookie, Optional target) throws InterruptedException { - long startMsecs = System.currentTimeMillis(); - Optional freeDiskSpace = Optional.empty(); - while (System.currentTimeMillis() < (startMsecs + MS_WEIGHT_UPDATE_TIMEOUT)) { - freeDiskSpace = bookieInfoReader.getFreeDiskSpace(bookie); - if (freeDiskSpace.equals(target)) { - return; - } - Thread.sleep(1000); - } - fail(String.format( - "Server %s still has weight %s rather than %s", - bookie.toString(), freeDiskSpace, target.toString())); - } - } - - private BookieServer restartBookie( - BookKeeperCheckInfoReader client, ServerConfiguration conf, final long initialFreeDiskSpace, - final long finalFreeDiskSpace, final AtomicBoolean useFinal) throws Exception { - final AtomicBoolean ready = useFinal == null ? new AtomicBoolean(false) : useFinal; - Bookie bookieWithCustomFreeDiskSpace = new TestBookieImpl(conf) { - long startTime = System.currentTimeMillis(); - @Override - public long getTotalFreeSpace() { - if (startTime == 0) { - startTime = System.currentTimeMillis(); - } - if (!ready.get()) { - return initialFreeDiskSpace; - } else { - // after delaySecs, advertise finalFreeDiskSpace; before that advertise initialFreeDiskSpace - return finalFreeDiskSpace; - } - } - }; - BookieServer server = startAndAddBookie(conf, bookieWithCustomFreeDiskSpace).getServer(); - client.blockUntilBookieWeightIs(server.getBookieId(), Optional.of(initialFreeDiskSpace)); - if (useFinal == null) { - ready.set(true); - } - return server; - } - - private BookieServer replaceBookieWithCustomFreeDiskSpaceBookie( - BookKeeperCheckInfoReader client, - int bookieIdx, final long freeDiskSpace) - throws Exception { - return replaceBookieWithCustomFreeDiskSpaceBookie(client, bookieIdx, freeDiskSpace, freeDiskSpace, null); - } - - private BookieServer replaceBookieWithCustomFreeDiskSpaceBookie( - BookKeeperCheckInfoReader client, - BookieServer bookie, final long freeDiskSpace) - throws Exception { - for (int i = 0; i < bookieCount(); i++) { - if (addressByIndex(i).equals(bookie.getBookieId())) { - return replaceBookieWithCustomFreeDiskSpaceBookie(client, i, freeDiskSpace); - } - } - return null; - } - - private BookieServer replaceBookieWithCustomFreeDiskSpaceBookie( - BookKeeperCheckInfoReader client, - int bookieIdx, long initialFreeDiskSpace, - long finalFreeDiskSpace, AtomicBoolean useFinal) throws Exception { - BookieId addr = addressByIndex(bookieIdx); - LOG.info("Killing bookie {}", addr); - ServerConfiguration conf = killBookieAndWaitForZK(bookieIdx); - client.blockUntilBookieWeightIs(addr, Optional.empty()); - return restartBookie(client, conf, initialFreeDiskSpace, finalFreeDiskSpace, useFinal); - } - - /** - * Test to show that weight based selection honors the disk weight of bookies. - */ - @FlakyTest("https://github.com/apache/bookkeeper/issues/503") - public void testDiskSpaceWeightedBookieSelection() throws Exception { - long freeDiskSpace = 1000000L; - int multiple = 3; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setDiskWeightBasedPlacementEnabled(true) - .setGetBookieInfoRetryIntervalSeconds(1, TimeUnit.SECONDS) - .setBookieMaxWeightMultipleForWeightBasedPlacement(multiple) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - final BookKeeperCheckInfoReader client = new BookKeeperCheckInfoReader(conf); - - for (int i = 0; i < numBookies; i++) { - // the first 8 bookies have freeDiskSpace of 1MB; While the remaining 2 have 3MB - if (i < numBookies - 2) { - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, freeDiskSpace); - } else { - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, multiple * freeDiskSpace); - } - } - Map m = new HashMap<>(); - bookieAddresses().forEach(a -> m.put(a, 0)); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - client.close(); - // make sure that bookies with higher weight(the last 2 bookies) are chosen 3X as often as the median; - // since the number of ledgers created is small (2000), we allow a range of 2X to 4X instead of the exact 3X - for (int i = 0; i < numBookies - 2; i++) { - double ratio1 = (double) m.get(addressByIndex(numBookies - 2)) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio1 - multiple), - Math.abs(ratio1 - multiple) < 1); - double ratio2 = (double) m.get(addressByIndex(numBookies - 1)) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio2 - multiple), - Math.abs(ratio2 - multiple) < 1); - } - } - - /** - * Test to show that weight based selection honors the disk weight of bookies and also adapts - * when the bookies's weight changes. - */ - @FlakyTest("https://github.com/apache/bookkeeper/issues/503") - public void testDiskSpaceWeightedBookieSelectionWithChangingWeights() throws Exception { - long freeDiskSpace = 1000000L; - int multiple = 3; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setDiskWeightBasedPlacementEnabled(true) - .setGetBookieInfoRetryIntervalSeconds(1, TimeUnit.SECONDS) - .setBookieMaxWeightMultipleForWeightBasedPlacement(multiple) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - final BookKeeperCheckInfoReader client = new BookKeeperCheckInfoReader(conf); - - for (int i = 0; i < numBookies; i++) { - // the first 8 bookies have freeDiskSpace of 1MB; While the remaining 2 have 3MB - if (i < numBookies - 2) { - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, freeDiskSpace); - } else { - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, multiple * freeDiskSpace); - } - } - Map m = new HashMap<>(); - bookieAddresses().forEach(a -> m.put(a, 0)); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - // make sure that bookies with higher weight(the last 2 bookies) are chosen 3X as often as the median; - // since the number of ledgers created is small (2000), we allow a range of 2X to 4X instead of the exact 3X - for (int i = 0; i < numBookies - 2; i++) { - double ratio1 = (double) m.get(addressByIndex(numBookies - 2)) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio1 - multiple), - Math.abs(ratio1 - multiple) < 1); - double ratio2 = (double) m.get(addressByIndex(numBookies - 1)) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio2 - multiple), - Math.abs(ratio2 - multiple) < 1); - } - - // Restart the bookies in such a way that the first 2 bookies go from 1MB to 3MB free space and the last - // 2 bookies go from 3MB to 1MB - BookieServer server1 = serverByIndex(0); - BookieServer server2 = serverByIndex(1); - BookieServer server3 = serverByIndex(numBookies - 2); - BookieServer server4 = serverByIndex(numBookies - 1); - - server1 = replaceBookieWithCustomFreeDiskSpaceBookie(client, server1, multiple * freeDiskSpace); - server2 = replaceBookieWithCustomFreeDiskSpaceBookie(client, server2, multiple * freeDiskSpace); - server3 = replaceBookieWithCustomFreeDiskSpaceBookie(client, server3, freeDiskSpace); - server4 = replaceBookieWithCustomFreeDiskSpaceBookie(client, server4, freeDiskSpace); - - bookieAddresses().forEach(a -> m.put(a, 0)); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - // make sure that bookies with higher weight(the last 2 bookies) are chosen 3X as often as the median; - // since the number of ledgers created is small (2000), we allow a range of 2X to 4X instead of the exact 3X - for (int i = 0; i < numBookies; i++) { - if (server1.getLocalAddress().equals(addressByIndex(i)) - || server2.getLocalAddress().equals(addressByIndex(i))) { - continue; - } - double ratio1 = (double) m.get(server1) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio1 - multiple), - Math.abs(ratio1 - multiple) < 1); - double ratio2 = (double) m.get(server2) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio2 - multiple), - Math.abs(ratio2 - multiple) < 1); - } - client.close(); - } - - /** - * Test to show that weight based selection honors the disk weight of bookies and also adapts - * when bookies go away permanently. - */ - @FlakyTest("https://github.com/apache/bookkeeper/issues/503") - public void testDiskSpaceWeightedBookieSelectionWithBookiesDying() throws Exception { - long freeDiskSpace = 1000000L; - int multiple = 3; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setDiskWeightBasedPlacementEnabled(true) - .setGetBookieInfoRetryIntervalSeconds(1, TimeUnit.SECONDS) - .setBookieMaxWeightMultipleForWeightBasedPlacement(multiple) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - final BookKeeperCheckInfoReader client = new BookKeeperCheckInfoReader(conf); - - for (int i = 0; i < numBookies; i++) { - // the first 8 bookies have freeDiskSpace of 1MB; While the remaining 2 have 1GB - if (i < numBookies - 2) { - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, freeDiskSpace); - } else { - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, multiple * freeDiskSpace); - } - } - Map m = new HashMap<>(); - bookieAddresses().forEach(a -> m.put(a, 0)); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - // make sure that bookies with higher weight are chosen 3X as often as the median; - // since the number of ledgers is small (2000), there may be variation - double ratio1 = (double) m.get(addressByIndex(numBookies - 2)) - / (double) m.get(addressByIndex(0)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio1 - multiple), - Math.abs(ratio1 - multiple) < 1); - double ratio2 = (double) m.get(addressByIndex(numBookies - 1)) - / (double) m.get(addressByIndex(1)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio2 - multiple), - Math.abs(ratio2 - multiple) < 1); - - // Bring down the 2 bookies that had higher weight; after this the allocation to all - // the remaining bookies should be uniform - bookieAddresses().forEach(a -> m.put(a, 0)); - - BookieServer server1 = serverByIndex(numBookies - 2); - BookieServer server2 = serverByIndex(numBookies - 1); - killBookieAndWaitForZK(numBookies - 1); - killBookieAndWaitForZK(numBookies - 2); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - // make sure that bookies with higher weight are chosen 3X as often as the median; - for (int i = 0; i < numBookies - 3; i++) { - double delta = Math.abs((double) m.get(addressByIndex(i)) - - (double) m.get(addressByIndex(i + 1))); - delta = (delta * 100) / (double) m.get(addressByIndex(i + 1)); - // the deviation should be less than 30% - assertTrue("Weigheted placement is not honored: " + delta, delta <= 30); - } - // since the following 2 bookies were down, they shouldn't ever be selected - assertTrue("Weigheted placement is not honored" + m.get(server1), - m.get(server1) == 0); - assertTrue("Weigheted placement is not honored" + m.get(server2), - m.get(server2) == 0); - - client.close(); - } - - /** - * Test to show that weight based selection honors the disk weight of bookies and also adapts - * when bookies are added. - */ - @FlakyTest("https://github.com/apache/bookkeeper/issues/503") - public void testDiskSpaceWeightedBookieSelectionWithBookiesBeingAdded() throws Exception { - long freeDiskSpace = 1000000L; - int multiple = 3; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setDiskWeightBasedPlacementEnabled(true) - .setGetBookieInfoRetryIntervalSeconds(1, TimeUnit.SECONDS) - .setBookieMaxWeightMultipleForWeightBasedPlacement(multiple) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - final BookKeeperCheckInfoReader client = new BookKeeperCheckInfoReader(conf); - - for (int i = 0; i < numBookies; i++) { - // all the bookies have freeDiskSpace of 1MB - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, freeDiskSpace); - } - // let the last two bookies be down initially - ServerConfiguration conf1 = killBookieAndWaitForZK(numBookies - 1); - ServerConfiguration conf2 = killBookieAndWaitForZK(numBookies - 2); - Map m = new HashMap<>(); - - bookieAddresses().forEach(a -> m.put(a, 0)); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - // make sure that bookies with higher weight are chosen 3X as often as the median; - // since the number of ledgers is small (2000), there may be variation - for (int i = 0; i < numBookies - 3; i++) { - double delta = Math.abs((double) m.get(addressByIndex(i)) - - (double) m.get(addressByIndex(i + 1))); - delta = (delta * 100) / (double) m.get(addressByIndex(i + 1)); - // the deviation should be less than 30% - assertTrue("Weigheted placement is not honored: " + delta, delta <= 30); - } - - // bring up the two dead bookies; they'll also have 3X more free space than the rest of the bookies - restartBookie(client, conf1, multiple * freeDiskSpace, multiple * freeDiskSpace, null); - restartBookie(client, conf2, multiple * freeDiskSpace, multiple * freeDiskSpace, null); - - bookieAddresses().forEach(a -> m.put(a, 0)); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - // make sure that bookies with higher weight(the last 2 bookies) are chosen 3X as often as the median; - // since the number of ledgers created is small (2000), we allow a range of 2X to 4X instead of the exact 3X - for (int i = 0; i < numBookies - 2; i++) { - double ratio1 = (double) m.get(addressByIndex(numBookies - 2)) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio1 - multiple), - Math.abs(ratio1 - multiple) < 1); - double ratio2 = (double) m.get(addressByIndex(numBookies - 1)) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio2 - multiple), - Math.abs(ratio2 - multiple) < 1); - } - client.close(); - } - - /** - * Tests that the bookie selection is based on the amount of free disk space a bookie has. Also make sure that - * the periodic bookieInfo read is working and causes the new weights to be taken into account. - */ - @FlakyTest("https://github.com/apache/bookkeeper/issues/503") - public void testDiskSpaceWeightedBookieSelectionWithPeriodicBookieInfoUpdate() throws Exception { - long freeDiskSpace = 1000000L; - int multiple = 3; - - int updateIntervalSecs = 6; - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setDiskWeightBasedPlacementEnabled(true) - .setGetBookieInfoRetryIntervalSeconds(1, TimeUnit.SECONDS) - .setBookieMaxWeightMultipleForWeightBasedPlacement(multiple) - .setGetBookieInfoIntervalSeconds(updateIntervalSecs, TimeUnit.SECONDS); - final BookKeeperCheckInfoReader client = new BookKeeperCheckInfoReader(conf); - - AtomicBoolean useHigherValue = new AtomicBoolean(false); - for (int i = 0; i < numBookies; i++) { - // the first 8 bookies have freeDiskSpace of 1MB; the remaining 2 will advertise 1MB for - // the start of the test, and 3MB once useHigherValue is set - if (i < numBookies - 2) { - replaceBookieWithCustomFreeDiskSpaceBookie(client, 0, freeDiskSpace); - } else { - replaceBookieWithCustomFreeDiskSpaceBookie( - client, 0, freeDiskSpace, multiple * freeDiskSpace, useHigherValue); - } - } - Map m = new HashMap<>(); - - bookieAddresses().forEach(a -> m.put(a, 0)); - - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - for (int i = 0; i < numBookies - 1; i++) { - double delta = Math.abs((double) m.get(addressByIndex(i)) - - (double) m.get(addressByIndex(i + 1))); - delta = (delta * 100) / (double) m.get(addressByIndex(i + 1)); - assertTrue("Weigheted placement is not honored: " + delta, delta <= 30); // the deviation should be <30% - } - - - // Sleep for double the time required to update the bookie infos, and then check each one - useHigherValue.set(true); - Thread.sleep(updateIntervalSecs * 1000); - for (int i = 0; i < numBookies; i++) { - if (i < numBookies - 2) { - client.blockUntilBookieWeightIs(addressByIndex(i), Optional.of(freeDiskSpace)); - } else { - client.blockUntilBookieWeightIs(addressByIndex(i), Optional.of(freeDiskSpace * multiple)); - } - } - - bookieAddresses().forEach(a -> m.put(a, 0)); - for (int i = 0; i < 2000; i++) { - LedgerHandle lh = client.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - for (BookieId b : lh.getLedgerMetadata().getEnsembleAt(0)) { - m.put(b, m.get(b) + 1); - } - } - - // make sure that bookies with higher weight(the last 2 bookies) are chosen 3X as often as the median; - // since the number of ledgers created is small (2000), we allow a range of 2X to 4X instead of the exact 3X - for (int i = 0; i < numBookies - 2; i++) { - double ratio1 = (double) m.get(addressByIndex(numBookies - 2)) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio1 - multiple), - Math.abs(ratio1 - multiple) < 1); - double ratio2 = (double) m.get(addressByIndex(lastBookieIndex())) - / (double) m.get(addressByIndex(i)); - assertTrue("Weigheted placement is not honored: " + Math.abs(ratio2 - multiple), - Math.abs(ratio2 - multiple) < 1); - } - - client.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java deleted file mode 100644 index fd0a2a9b76a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java +++ /dev/null @@ -1,1309 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.BookKeeperClientStats.WRITE_DELAYED_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS; -import static org.apache.bookkeeper.client.BookKeeperClientStats.WRITE_TIMED_OUT_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.util.IllegalReferenceCountException; -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BKException.BKBookieHandleNotAvailableException; -import org.apache.bookkeeper.client.BKException.BKIllegalOpException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.apache.bookkeeper.zookeeper.BoundExponentialBackoffRetryPolicy; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.bookkeeper.zookeeper.ZooKeeperWatcherBase; -import org.apache.zookeeper.AsyncCallback.StringCallback; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.KeeperException.ConnectionLossException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.ZooKeeper.States; -import org.apache.zookeeper.data.ACL; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests of the main BookKeeper client. - */ -public class BookKeeperTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(BookKeeperTest.class); - private static final long INVALID_LEDGERID = -1L; - private final DigestType digestType; - - public BookKeeperTest() { - super(3); - this.digestType = DigestType.CRC32; - } - - @Test - public void testConstructionZkDelay() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setZkTimeout(20000); - - CountDownLatch l = new CountDownLatch(1); - zkUtil.sleepCluster(200, TimeUnit.MILLISECONDS, l); - l.await(); - - BookKeeper bkc = new BookKeeper(conf); - bkc.createLedger(digestType, "testPasswd".getBytes()).close(); - bkc.close(); - } - - @Test - public void testConstructionNotConnectedExplicitZk() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setZkTimeout(20000); - - CountDownLatch l = new CountDownLatch(1); - zkUtil.sleepCluster(200, TimeUnit.MILLISECONDS, l); - l.await(); - - ZooKeeper zk = new ZooKeeper( - zkUtil.getZooKeeperConnectString(), - 50, - event -> {}); - assertFalse("ZK shouldn't have connected yet", zk.getState().isConnected()); - try { - BookKeeper bkc = new BookKeeper(conf, zk); - fail("Shouldn't be able to construct with unconnected zk"); - } catch (IOException cle) { - // correct behaviour - assertTrue(cle.getCause() instanceof ConnectionLossException); - } - } - - /** - * Test that bookkeeper is not able to open ledgers if - * it provides the wrong password or wrong digest. - */ - @Test - public void testBookkeeperDigestPasswordWithAutoDetection() throws Exception { - testBookkeeperDigestPassword(true); - } - - @Test - public void testBookkeeperDigestPasswordWithoutAutoDetection() throws Exception { - testBookkeeperDigestPassword(false); - } - - void testBookkeeperDigestPassword(boolean autodetection) throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setEnableDigestTypeAutodetection(autodetection); - BookKeeper bkc = new BookKeeper(conf); - - DigestType digestCorrect = digestType; - byte[] passwdCorrect = "AAAAAAA".getBytes(); - DigestType digestBad = digestType == DigestType.MAC ? DigestType.CRC32 : DigestType.MAC; - byte[] passwdBad = "BBBBBBB".getBytes(); - - - LedgerHandle lh = null; - try { - lh = bkc.createLedger(digestCorrect, passwdCorrect); - long id = lh.getId(); - for (int i = 0; i < 100; i++) { - lh.addEntry("foobar".getBytes()); - } - lh.close(); - - // try open with bad passwd - try { - bkc.openLedger(id, digestCorrect, passwdBad); - fail("Shouldn't be able to open with bad passwd"); - } catch (BKException.BKUnauthorizedAccessException bke) { - // correct behaviour - } - - // try open with bad digest - try { - bkc.openLedger(id, digestBad, passwdCorrect); - if (!autodetection) { - fail("Shouldn't be able to open with bad digest"); - } - } catch (BKException.BKDigestMatchException bke) { - // correct behaviour - if (autodetection) { - fail("Should not throw digest match exception if `autodetection` is enabled"); - } - } - - // try open with both bad - try { - bkc.openLedger(id, digestBad, passwdBad); - fail("Shouldn't be able to open with bad passwd and digest"); - } catch (BKException.BKUnauthorizedAccessException bke) { - // correct behaviour - } - - // try open with both correct - bkc.openLedger(id, digestCorrect, passwdCorrect).close(); - } finally { - if (lh != null) { - lh.close(); - } - bkc.close(); - } - } - - /** - * Tests that when trying to use a closed BK client object we get - * a callback error and not an InterruptedException. - * @throws Exception - */ - @Test - public void testAsyncReadWithError() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "testPasswd".getBytes()); - bkc.close(); - - final AtomicInteger result = new AtomicInteger(0); - final CountDownLatch counter = new CountDownLatch(1); - - // Try to write, we shoud get and error callback but not an exception - lh.asyncAddEntry("test".getBytes(), new AddCallback() { - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - result.set(rc); - counter.countDown(); - } - }, null); - - counter.await(); - - assertTrue(result.get() != 0); - } - - /** - * Test that bookkeeper will close cleanly if close is issued - * while another operation is in progress. - */ - @Test - public void testCloseDuringOp() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - for (int i = 0; i < 10; i++) { - final BookKeeper client = new BookKeeper(conf); - final CountDownLatch l = new CountDownLatch(1); - final AtomicBoolean success = new AtomicBoolean(false); - Thread t = new Thread() { - public void run() { - try { - LedgerHandle lh = client.createLedger(3, 3, digestType, "testPasswd".getBytes()); - startNewBookie(); - killBookie(0); - lh.asyncAddEntry("test".getBytes(), new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - // noop, we don't care if this completes - } - }, null); - client.close(); - success.set(true); - l.countDown(); - } catch (Exception e) { - LOG.error("Error running test", e); - success.set(false); - l.countDown(); - } - } - }; - t.start(); - assertTrue("Close never completed", l.await(10, TimeUnit.SECONDS)); - assertTrue("Close was not successful", success.get()); - } - } - - @Test - public void testIsClosed() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - LedgerHandle lh = bkc.createLedger(digestType, "testPasswd".getBytes()); - Long lId = lh.getId(); - - lh.addEntry("000".getBytes()); - boolean result = bkc.isClosed(lId); - assertTrue("Ledger shouldn't be flagged as closed!", !result); - - lh.close(); - result = bkc.isClosed(lId); - assertTrue("Ledger should be flagged as closed!", result); - - bkc.close(); - } - - @Test - public void testReadFailureCallback() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - LedgerHandle lh = bkc.createLedger(digestType, "testPasswd".getBytes()); - - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("entry-" + i).getBytes()); - } - - stopBKCluster(); - - try { - lh.readEntries(0, numEntries - 1); - fail("Read operation should have failed"); - } catch (BKBookieHandleNotAvailableException e) { - // expected - } - - final CountDownLatch counter = new CountDownLatch(1); - final AtomicInteger receivedResponses = new AtomicInteger(0); - final AtomicInteger returnCode = new AtomicInteger(); - lh.asyncReadEntries(0, numEntries - 1, new ReadCallback() { - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - returnCode.set(rc); - receivedResponses.incrementAndGet(); - counter.countDown(); - } - }, null); - - counter.await(); - - // Wait extra time to ensure no extra responses received - Thread.sleep(1000); - - assertEquals(1, receivedResponses.get()); - assertEquals(BKException.Code.BookieHandleNotAvailableException, returnCode.get()); - - bkc.close(); - } - - @Test - public void testAutoCloseableBookKeeper() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc2; - try (BookKeeper bkc = new BookKeeper(conf)) { - bkc2 = bkc; - long ledgerId; - try (LedgerHandle lh = bkc.createLedger(digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < 100; i++) { - lh.addEntry("foobar".getBytes()); - } - } - assertTrue("Ledger should be closed!", bkc.isClosed(ledgerId)); - } - assertTrue("BookKeeper should be closed!", bkc2.closed); - } - - @Test - public void testReadAfterLastAddConfirmed() throws Exception { - - ClientConfiguration clientConfiguration = new ClientConfiguration(); - clientConfiguration.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - try (BookKeeper bkWriter = new BookKeeper(clientConfiguration)) { - LedgerHandle writeLh = bkWriter.createLedger(digestType, "testPasswd".getBytes()); - long ledgerId = writeLh.getId(); - int numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - writeLh.addEntry(("foobar" + i).getBytes()); - } - - try (BookKeeper bkReader = new BookKeeper(clientConfiguration); - LedgerHandle rlh = bkReader.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes())) { - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - assertFalse(writeLh.isClosed()); - - // with readUnconfirmedEntries we are able to read all of the entries - Enumeration entries = rlh.readUnconfirmedEntries(0, numOfEntries - 1); - int entryId = 0; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - String entryString = new String(entry.getEntry()); - assertTrue("Expected entry String: " + ("foobar" + entryId) - + " actual entry String: " + entryString, - entryString.equals("foobar" + entryId)); - entryId++; - } - } - - try (BookKeeper bkReader = new BookKeeper(clientConfiguration); - LedgerHandle rlh = bkReader.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes())) { - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - assertFalse(writeLh.isClosed()); - - // without readUnconfirmedEntries we are not able to read all of the entries - try { - rlh.readEntries(0, numOfEntries - 1); - fail("shoud not be able to read up to " + (numOfEntries - 1) + " with readEntries"); - } catch (BKException.BKReadException expected) { - } - - // read all entries within the 0..LastAddConfirmed range with readEntries - assertEquals(rlh.getLastAddConfirmed() + 1, - Collections.list(rlh.readEntries(0, rlh.getLastAddConfirmed())).size()); - - // assert local LAC does not change after reads - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - // read all entries within the 0..LastAddConfirmed range with readUnconfirmedEntries - assertEquals(rlh.getLastAddConfirmed() + 1, - Collections.list(rlh.readUnconfirmedEntries(0, rlh.getLastAddConfirmed())).size()); - - // assert local LAC does not change after reads - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - // read all entries within the LastAddConfirmed..numOfEntries - 1 range with readUnconfirmedEntries - assertEquals(numOfEntries - rlh.getLastAddConfirmed(), - Collections.list(rlh.readUnconfirmedEntries(rlh.getLastAddConfirmed(), numOfEntries - 1)).size()); - - // assert local LAC does not change after reads - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - try { - // read all entries within the LastAddConfirmed..numOfEntries range with readUnconfirmedEntries - // this is an error, we are going outside the range of existing entries - rlh.readUnconfirmedEntries(rlh.getLastAddConfirmed(), numOfEntries); - fail("the read tried to access data for unexisting entry id " + numOfEntries); - } catch (BKException.BKNoSuchEntryException expected) { - // expecting a BKNoSuchEntryException, as the entry does not exist on bookies - } - - try { - // read all entries within the LastAddConfirmed..numOfEntries range with readEntries - // this is an error, we are going outside the range of existing entries - rlh.readEntries(rlh.getLastAddConfirmed(), numOfEntries); - fail("the read tries to access data for unexisting entry id " + numOfEntries); - } catch (BKException.BKReadException expected) { - // expecting a BKReadException, as the client rejected the request to access entries - // after local LastAddConfirmed - } - - } - - // ensure that after restarting every bookie entries are not lost - // even entries after the LastAddConfirmed - restartBookies(); - - try (BookKeeper bkReader = new BookKeeper(clientConfiguration); - LedgerHandle rlh = bkReader.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes())) { - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - assertFalse(writeLh.isClosed()); - - // with readUnconfirmedEntries we are able to read all of the entries - Enumeration entries = rlh.readUnconfirmedEntries(0, numOfEntries - 1); - int entryId = 0; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - String entryString = new String(entry.getEntry()); - assertTrue("Expected entry String: " + ("foobar" + entryId) - + " actual entry String: " + entryString, - entryString.equals("foobar" + entryId)); - entryId++; - } - } - - try (BookKeeper bkReader = new BookKeeper(clientConfiguration); - LedgerHandle rlh = bkReader.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes())) { - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - assertFalse(writeLh.isClosed()); - - // without readUnconfirmedEntries we are not able to read all of the entries - try { - rlh.readEntries(0, numOfEntries - 1); - fail("shoud not be able to read up to " + (numOfEntries - 1) + " with readEntries"); - } catch (BKException.BKReadException expected) { - } - - // read all entries within the 0..LastAddConfirmed range with readEntries - assertEquals(rlh.getLastAddConfirmed() + 1, - Collections.list(rlh.readEntries(0, rlh.getLastAddConfirmed())).size()); - - // assert local LAC does not change after reads - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - // read all entries within the 0..LastAddConfirmed range with readUnconfirmedEntries - assertEquals(rlh.getLastAddConfirmed() + 1, - Collections.list(rlh.readUnconfirmedEntries(0, rlh.getLastAddConfirmed())).size()); - - // assert local LAC does not change after reads - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - // read all entries within the LastAddConfirmed..numOfEntries - 1 range with readUnconfirmedEntries - assertEquals(numOfEntries - rlh.getLastAddConfirmed(), - Collections.list(rlh.readUnconfirmedEntries(rlh.getLastAddConfirmed(), numOfEntries - 1)).size()); - - // assert local LAC does not change after reads - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - try { - // read all entries within the LastAddConfirmed..numOfEntries range with readUnconfirmedEntries - // this is an error, we are going outside the range of existing entries - rlh.readUnconfirmedEntries(rlh.getLastAddConfirmed(), numOfEntries); - fail("the read tried to access data for unexisting entry id " + numOfEntries); - } catch (BKException.BKNoSuchEntryException expected) { - // expecting a BKNoSuchEntryException, as the entry does not exist on bookies - } - - try { - // read all entries within the LastAddConfirmed..numOfEntries range with readEntries - // this is an error, we are going outside the range of existing entries - rlh.readEntries(rlh.getLastAddConfirmed(), numOfEntries); - fail("the read tries to access data for unexisting entry id " + numOfEntries); - } catch (BKException.BKReadException expected) { - // expecting a BKReadException, as the client rejected the request to access entries - // after local LastAddConfirmed - } - - } - - // open ledger with fencing, this will repair the ledger and make the last entry readable - try (BookKeeper bkReader = new BookKeeper(clientConfiguration); - LedgerHandle rlh = bkReader.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 1) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 1))); - - assertFalse(writeLh.isClosed()); - - // without readUnconfirmedEntries we are not able to read all of the entries - Enumeration entries = rlh.readEntries(0, numOfEntries - 1); - int entryId = 0; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - String entryString = new String(entry.getEntry()); - assertTrue("Expected entry String: " + ("foobar" + entryId) - + " actual entry String: " + entryString, - entryString.equals("foobar" + entryId)); - entryId++; - } - } - - // should still be able to close as long as recovery closed the ledger - // with the same last entryId and length as in the write handle. - writeLh.close(); - } - } - - @Test - public void testReadWriteWithV2WireProtocol() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setUseV2WireProtocol(true); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numEntries = 100; - byte[] data = "foobar".getBytes(); - try (BookKeeper bkc = new BookKeeper(conf)) { - - // basic read/write - { - long ledgerId; - try (LedgerHandle lh = bkc.createLedger(digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - } - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - for (Enumeration readEntries = lh.readEntries(0, numEntries - 1); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertArrayEquals(data, entry.getEntry()); - } - } - } - - // basic fencing - { - long ledgerId; - try (LedgerHandle lh2 = bkc.createLedger(digestType, "testPasswd".getBytes())) { - ledgerId = lh2.getId(); - lh2.addEntry(data); - try (LedgerHandle lh2Fence = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - } - try { - lh2.addEntry(data); - fail("ledger should be fenced"); - } catch (BKException.BKLedgerFencedException ex){ - } - } - } - } - } - - @Test - public void testBatchReadFailBackToSingleRead1() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numEntries = 100; - byte[] data = "foobar".getBytes(); - try (BookKeeper bkc = new BookKeeper(conf)) { - // basic read/write - { - long ledgerId; - try (LedgerHandle lh = bkc.createLedger(2, 2, 2, - digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - } - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - //V3 protocol not support batch read. In theory, it will throw UnsupportedOperationException. - try { - lh.batchReadEntries(0, numEntries, 5 * 1024 * 1024); - fail("Should throw UnsupportedOperationException."); - } catch (UnsupportedOperationException e) { - assertEquals("Unsupported batch read entry operation for v3 protocol.", e.getMessage()); - } - } - } - } - - try (BookKeeper bkc = new BookKeeper(conf)) { - // basic read/write - { - long ledgerId; - try (LedgerHandle lh = bkc.createLedger(3, 2, 2, - digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - } - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - //The ledger ensemble is not equals write quorum, so failback to single read, it also can - //read data successfully. - for (Enumeration readEntries = lh.batchReadEntries(0, numEntries, 5 * 1024 * 1024); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertArrayEquals(data, entry.getEntry()); - } - } - } - } - } - - @Test - public void testBatchReadFailBackToSingleRead2() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numEntries = 100; - byte[] data = "foobar".getBytes(); - try (BookKeeper bkc = new BookKeeper(conf)) { - // basic read/write - { - long ledgerId; - try (LedgerHandle lh = bkc.createLedger(2, 2, 2, - digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - } - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - //V3 protocol not support batch read, it will throw UnsupportedOperationException. - try { - lh.batchReadEntries(0, numEntries, 5 * 1024 * 1024); - fail("Should throw UnsupportedOperationException."); - } catch (UnsupportedOperationException e) { - assertEquals("Unsupported batch read entry operation for v3 protocol.", e.getMessage()); - } - } - } - } - - conf.setBatchReadEnabled(false); - try (BookKeeper bkc = new BookKeeper(conf)) { - // basic read/write - { - long ledgerId; - try (LedgerHandle lh = bkc.createLedger(2, 2, 2, - digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - } - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - //We config disable the batch read, so failback to single read, it also can - //read data successfully. - for (Enumeration readEntries = lh.batchReadEntries(0, numEntries, 5 * 1024 * 1024); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertArrayEquals(data, entry.getEntry()); - } - } - } - } - } - - @Test - public void testBatchReadWithV2Protocol() throws Exception { - ClientConfiguration conf = new ClientConfiguration().setUseV2WireProtocol(true); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numEntries = 100; - byte[] data = "foobar".getBytes(); - try (BookKeeper bkc = new BookKeeper(conf)) { - // basic read/write - { - long ledgerId; - try (LedgerHandle lh = bkc.createLedger(2, 2, 2, digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - } - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - int entries = 0; - for (Enumeration readEntries = lh.batchReadEntries(0, numEntries, 5 * 1024 * 1024); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertArrayEquals(data, entry.getEntry()); - entries++; - } - assertEquals(numEntries, entries); - - //The maxCount is 0, the result is only limited by maxSize. - entries = 0; - for (Enumeration readEntries = lh.batchReadEntries(0, 0, 5 * 1024 * 1024); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertArrayEquals(data, entry.getEntry()); - entries++; - } - assertEquals(numEntries, entries); - - // one entry size = 8(ledgerId) + 8(entryId) + 8(lac) + 8(length) + 8(digest) + payload size - long entrySize = 8 + 8 + 8 + 8 + 8 + data.length; - //response header size. - int headerSize = 24 + 8 + 4; - //The maxCount is 0, the result is only limited by maxSize. - entries = 0; - int expectEntriesNum = 5; - for (Enumeration readEntries = lh.batchReadEntries(0, 0, - expectEntriesNum * entrySize + headerSize + (expectEntriesNum * 4)); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertArrayEquals(data, entry.getEntry()); - entries++; - } - assertEquals(expectEntriesNum, entries); - - //The maxCount is 100, the result entries reach maxSize limit. - entries = 0; - for (Enumeration readEntries = lh.batchReadEntries(0, 20, - expectEntriesNum * entrySize + headerSize + (expectEntriesNum * 4)); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertArrayEquals(data, entry.getEntry()); - entries++; - } - assertEquals(expectEntriesNum, entries); - } - } - } - } - - @SuppressWarnings("deprecation") - @Test - public void testReadEntryReleaseByteBufs() throws Exception { - ClientConfiguration confWriter = new ClientConfiguration(); - confWriter.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int numEntries = 10; - byte[] data = "foobar".getBytes(); - long ledgerId; - try (BookKeeper bkc = new BookKeeper(confWriter)) { - try (LedgerHandle lh = bkc.createLedger(digestType, "testPasswd".getBytes())) { - ledgerId = lh.getId(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - } - } - - // v2 protocol, using pooled buffers - ClientConfiguration confReader1 = new ClientConfiguration() - .setUseV2WireProtocol(true) - .setNettyUsePooledBuffers(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - try (BookKeeper bkc = new BookKeeper(confReader1)) { - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - for (Enumeration readEntries = lh.readEntries(0, numEntries - 1); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - try { - entry.data.release(); - } catch (IllegalReferenceCountException ok) { - fail("ByteBuf already released"); - } - } - } - } - - // v2 protocol, not using pooled buffers - ClientConfiguration confReader2 = new ClientConfiguration() - .setUseV2WireProtocol(true) - .setNettyUsePooledBuffers(false); - confReader2.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - try (BookKeeper bkc = new BookKeeper(confReader2)) { - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - for (Enumeration readEntries = lh.readEntries(0, numEntries - 1); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - try { - entry.data.release(); - } catch (IllegalReferenceCountException e) { - fail("ByteBuf already released"); - } - } - } - } - - // v3 protocol, not using pooled buffers - ClientConfiguration confReader3 = new ClientConfiguration() - .setUseV2WireProtocol(false) - .setNettyUsePooledBuffers(false) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try (BookKeeper bkc = new BookKeeper(confReader3)) { - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - for (Enumeration readEntries = lh.readEntries(0, numEntries - 1); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - assertTrue("Can't release entry " + entry.getEntryId() + ": ref = " + entry.data.refCnt(), - entry.data.release()); - try { - assertFalse(entry.data.release()); - fail("ByteBuf already released"); - } catch (IllegalReferenceCountException ok) { - } - } - } - } - - // v3 protocol, using pooled buffers - // v3 protocol from 4.5 always "wraps" buffers returned by protobuf - ClientConfiguration confReader4 = new ClientConfiguration() - .setUseV2WireProtocol(false) - .setNettyUsePooledBuffers(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - try (BookKeeper bkc = new BookKeeper(confReader4)) { - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - for (Enumeration readEntries = lh.readEntries(0, numEntries - 1); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - // ButeBufs not reference counter - assertTrue("Can't release entry " + entry.getEntryId() + ": ref = " + entry.data.refCnt(), - entry.data.release()); - try { - assertFalse(entry.data.release()); - fail("ByteBuf already released"); - } catch (IllegalReferenceCountException ok) { - } - } - } - } - - // cannot read twice an entry - ClientConfiguration confReader5 = new ClientConfiguration(); - confReader5.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try (BookKeeper bkc = new BookKeeper(confReader5)) { - try (LedgerHandle lh = bkc.openLedger(ledgerId, digestType, "testPasswd".getBytes())) { - assertEquals(numEntries - 1, lh.readLastConfirmed()); - for (Enumeration readEntries = lh.readEntries(0, numEntries - 1); - readEntries.hasMoreElements();) { - LedgerEntry entry = readEntries.nextElement(); - entry.getEntry(); - try { - entry.getEntry(); - fail("entry data accessed twice"); - } catch (IllegalStateException ok){ - } - try { - entry.getEntryInputStream(); - fail("entry data accessed twice"); - } catch (IllegalStateException ok){ - } - } - } - } - } - - /** - * Tests that issuing multiple reads for the same entry at the same time works as expected. - * - * @throws Exception - */ - @Test - public void testDoubleRead() throws Exception { - LedgerHandle lh = bkc.createLedger(digestType, "".getBytes()); - - lh.addEntry("test".getBytes()); - - // Read the same entry more times asynchronously - final int n = 10; - final CountDownLatch latch = new CountDownLatch(n); - for (int i = 0; i < n; i++) { - lh.asyncReadEntries(0, 0, new ReadCallback() { - public void readComplete(int rc, LedgerHandle lh, - Enumeration seq, Object ctx) { - if (rc == BKException.Code.OK) { - latch.countDown(); - } else { - fail("Read fail"); - } - } - }, null); - } - - latch.await(); - } - - /** - * Tests that issuing multiple reads for the same entry at the same time works as expected. - * - * @throws Exception - */ - @Test - public void testDoubleReadWithV2Protocol() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setUseV2WireProtocol(true); - BookKeeperTestClient bkc = new BookKeeperTestClient(conf); - LedgerHandle lh = bkc.createLedger(digestType, "".getBytes()); - - lh.addEntry("test".getBytes()); - - // Read the same entry more times asynchronously - final int n = 10; - final CountDownLatch latch = new CountDownLatch(n); - for (int i = 0; i < n; i++) { - lh.asyncReadEntries(0, 0, new ReadCallback() { - public void readComplete(int rc, LedgerHandle lh, - Enumeration seq, Object ctx) { - if (rc == BKException.Code.OK) { - latch.countDown(); - } else { - fail("Read fail"); - } - } - }, null); - } - - latch.await(); - bkc.close(); - } - - @Test(expected = BKIllegalOpException.class) - public void testCannotUseWriteFlagsOnV2Protocol() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setUseV2WireProtocol(true); - try (BookKeeperTestClient bkc = new BookKeeperTestClient(conf)) { - try (WriteHandle wh = result(bkc.newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(2) - .withPassword("".getBytes()) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .execute())) { - result(wh.appendAsync("test".getBytes())); - } - } - } - - @Test(expected = BKIllegalOpException.class) - public void testCannotUseForceOnV2Protocol() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setUseV2WireProtocol(true); - try (BookKeeperTestClient bkc = new BookKeeperTestClient(conf)) { - try (WriteHandle wh = result(bkc.newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(2) - .withPassword("".getBytes()) - .withWriteFlags(WriteFlag.NONE) - .execute())) { - result(wh.appendAsync("".getBytes())); - result(wh.force()); - } - } - } - - class MockZooKeeperClient extends ZooKeeperClient { - class MockZooKeeper extends ZooKeeper { - public MockZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) - throws IOException { - super(connectString, sessionTimeout, watcher, canBeReadOnly); - } - - @Override - public void create(final String path, byte[] data, List acl, CreateMode createMode, StringCallback cb, - Object ctx) { - StringCallback injectedCallback = new StringCallback() { - @Override - public void processResult(int rc, String path, Object ctx, String name) { - /** - * if ledgerIdToInjectFailure matches with the path of - * the node, then throw CONNECTIONLOSS error and then - * reset it to INVALID_LEDGERID. - */ - if (path.contains(ledgerIdToInjectFailure.toString())) { - ledgerIdToInjectFailure.set(INVALID_LEDGERID); - cb.processResult(KeeperException.Code.CONNECTIONLOSS.intValue(), path, ctx, name); - } else { - cb.processResult(rc, path, ctx, name); - } - } - }; - super.create(path, data, acl, createMode, injectedCallback, ctx); - } - } - - private final String connectString; - private final int sessionTimeoutMs; - private final ZooKeeperWatcherBase watcherManager; - private final AtomicLong ledgerIdToInjectFailure; - - MockZooKeeperClient(String connectString, int sessionTimeoutMs, ZooKeeperWatcherBase watcher, - AtomicLong ledgerIdToInjectFailure) throws IOException { - /* - * in OperationalRetryPolicy maxRetries is > 0. So in case of any - * RecoverableException scenario, it will retry. - */ - super(connectString, sessionTimeoutMs, watcher, - new BoundExponentialBackoffRetryPolicy(sessionTimeoutMs, sessionTimeoutMs, Integer.MAX_VALUE), - new BoundExponentialBackoffRetryPolicy(sessionTimeoutMs, sessionTimeoutMs, 3), - NullStatsLogger.INSTANCE, 1, 0, false); - this.connectString = connectString; - this.sessionTimeoutMs = sessionTimeoutMs; - this.watcherManager = watcher; - this.ledgerIdToInjectFailure = ledgerIdToInjectFailure; - } - - @Override - protected ZooKeeper createZooKeeper() throws IOException { - return new MockZooKeeper(this.connectString, this.sessionTimeoutMs, this.watcherManager, false); - } - } - - @Test - public void testZKConnectionLossForLedgerCreation() throws Exception { - int zkSessionTimeOut = 10000; - AtomicLong ledgerIdToInjectFailure = new AtomicLong(INVALID_LEDGERID); - ZooKeeperWatcherBase zooKeeperWatcherBase = new ZooKeeperWatcherBase(zkSessionTimeOut, - NullStatsLogger.INSTANCE); - MockZooKeeperClient zkFaultInjectionWrapper = new MockZooKeeperClient(zkUtil.getZooKeeperConnectString(), - zkSessionTimeOut, zooKeeperWatcherBase, ledgerIdToInjectFailure); - zkFaultInjectionWrapper.waitForConnection(); - assertEquals("zkFaultInjectionWrapper should be in connected state", States.CONNECTED, - zkFaultInjectionWrapper.getState()); - BookKeeper bk = new BookKeeper(baseClientConf, zkFaultInjectionWrapper); - long oldZkInstanceSessionId = zkFaultInjectionWrapper.getSessionId(); - long ledgerId = 567L; - LedgerHandle lh = bk.createLedgerAdv(ledgerId, 1, 1, 1, DigestType.CRC32, "".getBytes(), null); - lh.close(); - - /* - * trigger Expired event so that MockZooKeeperClient would run - * 'clientCreator' and create new zk handle. In this case it would - * create MockZooKeeper. - */ - zooKeeperWatcherBase.process(new WatchedEvent(EventType.None, KeeperState.Expired, "")); - zkFaultInjectionWrapper.waitForConnection(); - for (int i = 0; i < 10; i++) { - if (zkFaultInjectionWrapper.getState() == States.CONNECTED) { - break; - } - Thread.sleep(200); - } - assertEquals("zkFaultInjectionWrapper should be in connected state", States.CONNECTED, - zkFaultInjectionWrapper.getState()); - assertNotEquals("Session Id of old and new ZK instance should be different", oldZkInstanceSessionId, - zkFaultInjectionWrapper.getSessionId()); - ledgerId++; - ledgerIdToInjectFailure.set(ledgerId); - /** - * ledgerIdToInjectFailure is set to 'ledgerId', so zookeeper.create - * would return CONNECTIONLOSS error for the first time and when it is - * retried, as expected it would return NODEEXISTS error. - * - * AbstractZkLedgerManager.createLedgerMetadata should deal with this - * scenario appropriately. - */ - lh = bk.createLedgerAdv(ledgerId, 1, 1, 1, DigestType.CRC32, "".getBytes(), null); - lh.close(); - assertEquals("injectZnodeCreationNoNodeFailure should have been reset it to INVALID_LEDGERID", INVALID_LEDGERID, - ledgerIdToInjectFailure.get()); - lh = bk.openLedger(ledgerId, DigestType.CRC32, "".getBytes()); - lh.close(); - ledgerId++; - lh = bk.createLedgerAdv(ledgerId, 1, 1, 1, DigestType.CRC32, "".getBytes(), null); - lh.close(); - bk.close(); - } - - @Test - public void testLedgerDeletionIdempotency() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf); - long ledgerId = 789L; - LedgerHandle lh = bk.createLedgerAdv(ledgerId, 1, 1, 1, DigestType.CRC32, "".getBytes(), null); - lh.close(); - bk.deleteLedger(ledgerId); - bk.deleteLedger(ledgerId); - bk.close(); - } - - /** - * Mock of RackawareEnsemblePlacementPolicy. Overrides areAckedBookiesAdheringToPlacementPolicy to only return true - * when ackedBookies consists of writeQuorumSizeToUseForTesting bookies. - */ - public static class MockRackawareEnsemblePlacementPolicy extends RackawareEnsemblePlacementPolicy { - private int writeQuorumSizeToUseForTesting; - private CountDownLatch conditionFirstInvocationLatch; - - void setWriteQuorumSizeToUseForTesting(int writeQuorumSizeToUseForTesting) { - this.writeQuorumSizeToUseForTesting = writeQuorumSizeToUseForTesting; - } - - void setConditionFirstInvocationLatch(CountDownLatch conditionFirstInvocationLatch) { - this.conditionFirstInvocationLatch = conditionFirstInvocationLatch; - } - - @Override - public boolean areAckedBookiesAdheringToPlacementPolicy(Set ackedBookies, - int writeQuorumSize, - int ackQuorumSize) { - conditionFirstInvocationLatch.countDown(); - return ackedBookies.size() == writeQuorumSizeToUseForTesting; - } - } - - /** - * Test to verify that PendingAddOp waits for success condition from areAckedBookiesAdheringToPlacementPolicy - * before returning success to client. Also tests working of WRITE_DELAYED_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS and - * WRITE_TIMED_OUT_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS counters. - */ - @Test - public void testEnforceMinNumFaultDomainsForWrite() throws Exception { - byte[] data = "foobar".getBytes(); - byte[] password = "testPasswd".getBytes(); - - startNewBookie(); - startNewBookie(); - - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setEnsemblePlacementPolicy(MockRackawareEnsemblePlacementPolicy.class); - - conf.setAddEntryTimeout(2); - conf.setAddEntryQuorumTimeout(4); - conf.setEnforceMinNumFaultDomainsForWrite(true); - - TestStatsProvider statsProvider = new TestStatsProvider(); - - // Abnormal values for testing to prevent timeouts - BookKeeperTestClient bk = new BookKeeperTestClient(conf, statsProvider); - StatsLogger statsLogger = bk.getStatsLogger(); - - int ensembleSize = 3; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - - CountDownLatch countDownLatch = new CountDownLatch(1); - MockRackawareEnsemblePlacementPolicy currPlacementPolicy = - (MockRackawareEnsemblePlacementPolicy) bk.getPlacementPolicy(); - currPlacementPolicy.setConditionFirstInvocationLatch(countDownLatch); - currPlacementPolicy.setWriteQuorumSizeToUseForTesting(writeQuorumSize); - - BookieId bookieToSleep; - - try (LedgerHandle lh = bk.createLedger(ensembleSize, writeQuorumSize, ackQuorumSize, digestType, password)) { - CountDownLatch sleepLatchCase1 = new CountDownLatch(1); - CountDownLatch sleepLatchCase2 = new CountDownLatch(1); - - // Put all non ensemble bookies to sleep - LOG.info("Putting all non ensemble bookies to sleep."); - for (BookieId addr : bookieAddresses()) { - try { - if (!lh.getCurrentEnsemble().contains(addr)) { - sleepBookie(addr, sleepLatchCase2); - } - } catch (UnknownHostException ignored) {} - } - - Thread writeToLedger = new Thread(() -> { - try { - LOG.info("Initiating write for entry"); - long entryId = lh.addEntry(data); - LOG.info("Wrote entry with entryId = {}", entryId); - } catch (InterruptedException | BKException ignored) { - } - }); - - bookieToSleep = lh.getCurrentEnsemble().get(0); - - LOG.info("Putting picked bookie to sleep"); - sleepBookie(bookieToSleep, sleepLatchCase1); - - assertEquals(statsLogger - .getCounter(WRITE_DELAYED_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS) - .get() - .longValue(), 0); - - // Trying to write entry - writeToLedger.start(); - - // Waiting and checking to make sure that write has not succeeded - countDownLatch.await(conf.getAddEntryTimeout(), TimeUnit.SECONDS); - assertEquals("Write succeeded but should not have", -1, lh.lastAddConfirmed); - - // Wake the bookie - sleepLatchCase1.countDown(); - - // Waiting and checking to make sure that write has succeeded - writeToLedger.join(conf.getAddEntryTimeout() * 1000); - assertEquals("Write did not succeed but should have", 0, lh.lastAddConfirmed); - - assertEquals(statsLogger - .getCounter(WRITE_DELAYED_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS) - .get() - .longValue(), 1); - - // AddEntry thread for second scenario - Thread writeToLedger2 = new Thread(() -> { - try { - LOG.info("Initiating write for entry"); - long entryId = lh.addEntry(data); - LOG.info("Wrote entry with entryId = {}", entryId); - } catch (InterruptedException | BKException ignored) { - } - }); - - bookieToSleep = lh.getCurrentEnsemble().get(1); - - LOG.info("Putting picked bookie to sleep"); - sleepBookie(bookieToSleep, sleepLatchCase2); - - // Trying to write entry - writeToLedger2.start(); - - // Waiting and checking to make sure that write has failed - writeToLedger2.join((conf.getAddEntryQuorumTimeout() + 2) * 1000); - assertEquals("Write succeeded but should not have", 0, lh.lastAddConfirmed); - - sleepLatchCase2.countDown(); - - assertEquals(statsLogger.getCounter(WRITE_DELAYED_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS).get().longValue(), - 2); - - assertEquals(statsLogger.getCounter(WRITE_TIMED_OUT_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS).get().longValue(), - 1); - } - } - - @Test - public void testBookieAddressResolverPassedToDNSToSwitchMapping() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - StaticDNSResolver tested = new StaticDNSResolver(); - try (BookKeeper bkc = BookKeeper - .forConfig(conf) - .dnsResolver(tested) - .build()) { - bkc.createLedger(digestType, "testPasswd".getBytes()).close(); - assertSame(bkc.getBookieAddressResolver(), tested.getBookieAddressResolver()); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTestClient.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTestClient.java deleted file mode 100644 index d9917c4ec96..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTestClient.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.discover.RegistrationClient.RegistrationListener; -import org.apache.bookkeeper.meta.zk.ZKMetadataClientDriver; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieClient; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.zookeeper.ZooKeeper; - -/** - * Test BookKeeperClient which allows access to members we don't - * wish to expose in the public API. - */ -@Slf4j -public class BookKeeperTestClient extends BookKeeper { - TestStatsProvider statsProvider; - - public BookKeeperTestClient(ClientConfiguration conf, TestStatsProvider statsProvider) - throws IOException, InterruptedException, BKException { - super(conf, null, null, new UnpooledByteBufAllocator(false), - statsProvider == null ? NullStatsLogger.INSTANCE : statsProvider.getStatsLogger(""), - null, null, null); - this.statsProvider = statsProvider; - } - - public BookKeeperTestClient(ClientConfiguration conf, ZooKeeper zkc) - throws IOException, InterruptedException, BKException { - super(conf, zkc, null, new UnpooledByteBufAllocator(false), - NullStatsLogger.INSTANCE, null, null, null); - } - - public BookKeeperTestClient(ClientConfiguration conf) - throws InterruptedException, BKException, IOException { - this(conf, (TestStatsProvider) null); - } - - public ZooKeeper getZkHandle() { - return ((ZKMetadataClientDriver) metadataDriver).getZk(); - } - - public ClientConfiguration getConf() { - return super.getConf(); - } - - public BookieClient getBookieClient() { - return bookieClient; - } - - public Future waitForReadOnlyBookie(BookieId b) - throws Exception { - return waitForBookieInSet(b, false); - } - - public Future waitForWritableBookie(BookieId b) - throws Exception { - return waitForBookieInSet(b, true); - } - - /** - * Wait for bookie to appear in either the writable set of bookies, - * or the read only set of bookies. Also ensure that it doesn't exist - * in the other set before completing. - */ - private Future waitForBookieInSet(BookieId b, - boolean writable) throws Exception { - log.info("Wait for {} to become {}", - b, writable ? "writable" : "readonly"); - - CompletableFuture readOnlyFuture = new CompletableFuture<>(); - CompletableFuture writableFuture = new CompletableFuture<>(); - - RegistrationListener readOnlyListener = (bookies) -> { - boolean contains = bookies.getValue().contains(b); - if ((!writable && contains) || (writable && !contains)) { - readOnlyFuture.complete(null); - } - }; - RegistrationListener writableListener = (bookies) -> { - boolean contains = bookies.getValue().contains(b); - if ((writable && contains) || (!writable && !contains)) { - writableFuture.complete(null); - } - }; - - getMetadataClientDriver().getRegistrationClient().watchWritableBookies(writableListener); - getMetadataClientDriver().getRegistrationClient().watchReadOnlyBookies(readOnlyListener); - - if (writable) { - return writableFuture - .thenCompose(ignored -> getMetadataClientDriver().getRegistrationClient().getReadOnlyBookies()) - .thenCompose(readonlyBookies -> { - if (readonlyBookies.getValue().contains(b)) { - // if the bookie still shows up at readonly path, wait for it to disappear - return readOnlyFuture; - } else { - return FutureUtils.Void(); - } - }); - } else { - return readOnlyFuture - .thenCompose(ignored -> getMetadataClientDriver().getRegistrationClient().getWritableBookies()) - .thenCompose(writableBookies -> { - if (writableBookies.getValue().contains(b)) { - // if the bookie still shows up at writable path, wait for it to disappear - return writableFuture; - } else { - return FutureUtils.Void(); - } - }); - } - } - - public TestStatsProvider getTestStatsProvider() { - return statsProvider; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieAddressResolverDisabledTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieAddressResolverDisabledTest.java deleted file mode 100644 index 611e3e9674f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieAddressResolverDisabledTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieAddressResolver; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test of {@link BookieAddressResolverDisabled}. - */ -public class BookieAddressResolverDisabledTest { - - @Test - public void testResolve() { - BookieAddressResolver resolver = new BookieAddressResolverDisabled(); - - BookieSocketAddress addr1 = resolver.resolve(BookieId.parse("127.0.0.1:3181")); - Assert.assertEquals("127.0.0.1", addr1.getHostName()); - Assert.assertEquals(3181, addr1.getPort()); - - BookieSocketAddress addr2 = resolver.resolve(BookieId.parse("localhost:3182")); - Assert.assertEquals("localhost", addr2.getHostName()); - Assert.assertEquals(3182, addr2.getPort()); - - try { - resolver.resolve(BookieId.parse("foobar")); - Assert.fail("Non-legacy style bookie id should fail to resolve address"); - } catch (Exception e) { - Assert.assertTrue(e instanceof BookieAddressResolver.BookieIdNotResolvedException); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java deleted file mode 100644 index ffd96ed155b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.fail; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.BKException.BKIllegalOpException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.UnderreplicatedLedger; -import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Unit test of bookie decommission operations. - */ -@Slf4j -public class BookieDecommissionTest extends BookKeeperClusterTestCase { - - private static final int NUM_OF_BOOKIES = 6; - private static DigestType digestType = DigestType.CRC32; - private static final String PASSWORD = "testPasswd"; - - public BookieDecommissionTest() { - super(NUM_OF_BOOKIES, 480); - baseConf.setOpenLedgerRereplicationGracePeriod(String.valueOf(1000)); - setAutoRecoveryEnabled(true); - } - - @FlakyTest("https://github.com/apache/bookkeeper/issues/502") - @Test - public void testDecommissionBookie() throws Exception { - ZkLedgerUnderreplicationManager urLedgerMgr = new ZkLedgerUnderreplicationManager(baseClientConf, zkc); - BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString()); - - List ledgerIds = new LinkedList<>(); - - int numOfLedgers = 2 * NUM_OF_BOOKIES; - int numOfEntries = 2 * NUM_OF_BOOKIES; - for (int i = 0; i < numOfLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 2, digestType, PASSWORD.getBytes()); - ledgerIds.add(lh.getId()); - for (int j = 0; j < numOfEntries; j++) { - lh.addEntry("entry".getBytes()); - } - lh.close(); - } - /* - * create ledgers having empty segments (segment with no entries) - */ - for (int i = 0; i < numOfLedgers; i++) { - LedgerHandle emptylh = bkc.createLedger(3, 2, digestType, PASSWORD.getBytes()); - ledgerIds.add(emptylh.getId()); - emptylh.close(); - } - - try { - /* - * if we try to call decommissionBookie for a bookie which is not - * shutdown, then it should throw BKIllegalOpException - */ - bkAdmin.decommissionBookie(addressByIndex(0)); - fail("Expected BKIllegalOpException because that bookie is not shutdown yet"); - } catch (BKIllegalOpException bkioexc) { - // expected IllegalException - } - - ServerConfiguration killedBookieConf = killBookie(1); - /* - * this decommisionBookie should make sure that there are no - * underreplicated ledgers because of this bookie - */ - bkAdmin.decommissionBookie(BookieImpl.getBookieId(killedBookieConf)); - bkAdmin.triggerAudit(); - Thread.sleep(5000); - Iterator ledgersToRereplicate = urLedgerMgr.listLedgersToRereplicate(null); - if (ledgersToRereplicate.hasNext()) { - while (ledgersToRereplicate.hasNext()) { - Long ledgerId = ledgersToRereplicate.next().getLedgerId(); - log.error("Ledger: {} is underreplicated which is not expected", ledgerId); - } - fail("There are not supposed to be any underreplicatedledgers"); - } - - killedBookieConf = killBookie(0); - bkAdmin.decommissionBookie(BookieImpl.getBookieId(killedBookieConf)); - bkAdmin.triggerAudit(); - Thread.sleep(5000); - ledgersToRereplicate = urLedgerMgr.listLedgersToRereplicate(null); - if (ledgersToRereplicate.hasNext()) { - while (ledgersToRereplicate.hasNext()) { - Long ledgerId = ledgersToRereplicate.next().getLedgerId(); - log.error("Ledger: {} is underreplicated which is not expected", ledgerId); - } - fail("There are not supposed to be any underreplicatedledgers"); - } - bkAdmin.close(); - - for (Long id: ledgerIds) { - verifyNoFragmentsOnBookie(id, BookieImpl.getBookieId(killedBookieConf)); - } - } - - @Test - public void testDecommissionForLedgersWithMultipleSegmentsAndNotWriteClosed() throws Exception { - ZkLedgerUnderreplicationManager urLedgerMgr = new ZkLedgerUnderreplicationManager(baseClientConf, zkc); - BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString()); - int numOfEntries = 2 * NUM_OF_BOOKIES; - - LedgerHandle lh1 = bkc.createLedgerAdv(1L, numBookies, 3, 3, digestType, PASSWORD.getBytes(), null); - LedgerHandle lh2 = bkc.createLedgerAdv(2L, numBookies, 3, 3, digestType, PASSWORD.getBytes(), null); - LedgerHandle lh3 = bkc.createLedgerAdv(3L, numBookies, 3, 3, digestType, PASSWORD.getBytes(), null); - LedgerHandle lh4 = bkc.createLedgerAdv(4L, numBookies, 3, 3, digestType, PASSWORD.getBytes(), null); - for (int j = 0; j < numOfEntries; j++) { - lh1.addEntry(j, "data".getBytes()); - lh2.addEntry(j, "data".getBytes()); - lh3.addEntry(j, "data".getBytes()); - lh4.addEntry(j, "data".getBytes()); - } - - // avoiding autorecovery fencing the ledger - servers.forEach(srv -> srv.stopAutoRecovery()); - - startNewBookie(); - - assertEquals("Number of Available Bookies", NUM_OF_BOOKIES + 1, bkAdmin.getAvailableBookies().size()); - - BookieId killedBookieId = getBookie(0); - log.warn("Killing bookie {}", killedBookieId); - killBookie(0); - - /* - * since one of the bookie is killed, ensemble change happens when next - * write is made.So new fragment will be created for those 2 ledgers. - */ - for (int j = numOfEntries; j < 2 * numOfEntries; j++) { - lh1.addEntry(j, "data".getBytes()); - lh2.addEntry(j, "data".getBytes()); - } - - /* - * Here lh1 and lh2 have multiple fragments and are writeclosed. But lh3 and lh4 are - * not writeclosed and contains only one fragment. - */ - lh1.close(); - lh2.close(); - - servers.forEach(srv -> { - try { - srv.startAutoRecovery(); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - - /* - * If the last fragment of the ledger is underreplicated and if the - * ledger is not closed then it will remain underreplicated for - * openLedgerRereplicationGracePeriod (by default 30 secs, 1 in the test). For more - * info. Check BOOKKEEPER-237 and BOOKKEEPER-325. But later - * ReplicationWorker will fence the ledger. - */ - bkAdmin.decommissionBookie(killedBookieId); - bkAdmin.triggerAudit(); - Thread.sleep(5000); - Iterator ledgersToRereplicate = urLedgerMgr.listLedgersToRereplicate(null); - if (ledgersToRereplicate.hasNext()) { - while (ledgersToRereplicate.hasNext()) { - long ledgerId = ledgersToRereplicate.next().getLedgerId(); - log.error("Ledger: {} is underreplicated which is not expected", ledgerId); - } - fail("There are not supposed to be any underreplicatedledgers"); - } - bkAdmin.close(); - - verifyNoFragmentsOnBookie(1L, killedBookieId); - verifyNoFragmentsOnBookie(2L, killedBookieId); - verifyNoFragmentsOnBookie(3L, killedBookieId); - verifyNoFragmentsOnBookie(4L, killedBookieId); - } - - @Test - public void testDecommissionForEmptyLedgers() throws Exception { - ZkLedgerUnderreplicationManager urLedgerMgr = new ZkLedgerUnderreplicationManager(baseClientConf, zkc); - BookKeeperAdmin bkAdmin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString()); - - LedgerHandle lh1 = bkc.createLedgerAdv(1L, numBookies, numBookies - 1, numBookies - 1, - digestType, PASSWORD.getBytes(), null); - LedgerHandle lh2 = bkc.createLedgerAdv(2L, numBookies, numBookies - 1, numBookies - 1, - digestType, PASSWORD.getBytes(), null); - LedgerHandle lh3 = bkc.createLedgerAdv(3L, numBookies, numBookies - 1, numBookies - 1, - digestType, PASSWORD.getBytes(), null); - LedgerHandle lh4 = bkc.createLedgerAdv(4L, numBookies, numBookies - 1, numBookies - 1, - digestType, PASSWORD.getBytes(), null); - - lh1.close(); - lh2.close(); - - startNewBookie(); - - assertEquals("Number of Available Bookies", NUM_OF_BOOKIES + 1, bkAdmin.getAvailableBookies().size()); - - BookieId killedBookieId = getBookie(0); - log.warn("Killing bookie {}", killedBookieId); - killBookie(0); - assertEquals("Number of Available Bookies", NUM_OF_BOOKIES, bkAdmin.getAvailableBookies().size()); - - bkAdmin.decommissionBookie(killedBookieId); - bkAdmin.triggerAudit(); - Thread.sleep(5000); - Iterator ledgersToRereplicate = urLedgerMgr.listLedgersToRereplicate(null); - if (ledgersToRereplicate.hasNext()) { - while (ledgersToRereplicate.hasNext()) { - long ledgerId = ledgersToRereplicate.next().getLedgerId(); - log.error("Ledger: {} is underreplicated which is not expected. {}", - ledgerId, ledgersToRereplicate.next().getReplicaList()); - } - fail("There are not supposed to be any underreplicatedledgers"); - } - bkAdmin.close(); - - verifyNoFragmentsOnBookie(1L, killedBookieId); - verifyNoFragmentsOnBookie(2L, killedBookieId); - verifyNoFragmentsOnBookie(3L, killedBookieId); - verifyNoFragmentsOnBookie(4L, killedBookieId); - - lh3.close(); - lh4.close(); - } - - private void verifyNoFragmentsOnBookie(long ledgerId, BookieId bookieId) throws BKException, InterruptedException { - LedgerHandle lh = bkc.openLedgerNoRecovery(ledgerId, digestType, PASSWORD.getBytes()); - log.error("Ledger {} metadata: {}", ledgerId, lh.getLedgerMetadata()); - - lh.getLedgerMetadata().getAllEnsembles().forEach((num, bookies) -> { - bookies.forEach(id -> { - assertNotEquals(bookieId, id); - }); - }); - - lh.close(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieNetworkAddressChangeTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieNetworkAddressChangeTest.java deleted file mode 100644 index 4bf8287c677..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieNetworkAddressChangeTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException.BKBookieHandleNotAvailableException; -import org.apache.bookkeeper.client.api.BookKeeper; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.discover.ZKRegistrationClient; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Ignore; -import org.junit.Test; - -/** - * Tests of the main BookKeeper client and the BP-41 bookieAddressTracking feature. - */ -@Slf4j -public class BookieNetworkAddressChangeTest extends BookKeeperClusterTestCase { - - public BookieNetworkAddressChangeTest() { - super(1); - this.useUUIDasBookieId = true; - } - - @Test - public void testFollowBookieAddressChange() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try (BookKeeper bkc = BookKeeper.newBuilder(conf) - .build();) { - long lId; - try (WriteHandle h = bkc - .newCreateLedgerOp() - .withAckQuorumSize(1) - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withPassword(new byte[0]) - .execute() - .get();) { - lId = h.getId(); - h.append("foo".getBytes("utf-8")); - } - - // restart bookie, change port - // on metadata we have a bookieId, not the network address - restartBookies(c -> c); - - try (ReadHandle h = bkc - .newOpenLedgerOp() - .withLedgerId(lId) - .withRecovery(true) - .withPassword(new byte[0]) - .execute() - .get()) { - assertEquals(0, h.getLastAddConfirmed()); - try (LedgerEntries entries = h.read(0, 0);) { - assertEquals("foo", new String(entries.getEntry(0).getEntryBytes(), "utf-8")); - } - } - } - } - - @Test - @Ignore("PLSR-1850 Seems like restart of the bookie always comes up on same port hence failing this test") - public void testFollowBookieAddressChangeTrckingDisabled() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setEnableBookieAddressTracking(false); - try (BookKeeper bkc = BookKeeper.newBuilder(conf) - .build();) { - long lId; - try (WriteHandle h = bkc - .newCreateLedgerOp() - .withAckQuorumSize(1) - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withPassword(new byte[0]) - .execute() - .get();) { - lId = h.getId(); - h.append("foo".getBytes("utf-8")); - } - - // restart bookie, change port - // on metadata we have a bookieId, not the network address - restartBookie(getBookie(0)); - try (ReadHandle h = bkc - .newOpenLedgerOp() - .withLedgerId(lId) - .withRecovery(true) - .withPassword(new byte[0]) - .execute() - .get()) { - try (LedgerEntries entries = h.read(0, 0);) { - fail("Should not be able to connect to the bookie with Bookie Address Tracking Disabled"); - } catch (BKBookieHandleNotAvailableException expected) { - } - } - } - } - - @Test - public void testFollowBookieAddressChangeZkSessionExpire() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try (BookKeeper bkc = BookKeeper.newBuilder(conf) - .build();) { - long lId; - try (WriteHandle h = bkc - .newCreateLedgerOp() - .withAckQuorumSize(1) - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withPassword(new byte[0]) - .execute() - .get();) { - lId = h.getId(); - h.append("foo".getBytes("utf-8")); - } - - log.error("expiring ZK session!"); - // expire zk session - ZKRegistrationClient regClient = (ZKRegistrationClient) ((org.apache.bookkeeper.client.BookKeeper) bkc) - .getMetadataClientDriver() - .getRegistrationClient(); - - regClient.getZk().getTestable().injectSessionExpiration(); - - // restart bookie, change port - // on metadata we have a bookieId, not the network address - restartBookies(c -> c); - - try (ReadHandle h = bkc - .newOpenLedgerOp() - .withLedgerId(lId) - .withRecovery(true) - .withPassword(new byte[0]) - .execute() - .get()) { - assertEquals(0, h.getLastAddConfirmed()); - try (LedgerEntries entries = h.read(0, 0);) { - assertEquals("foo", new String(entries.getEntry(0).getEntryBytes(), "utf-8")); - } - } - } - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java deleted file mode 100644 index 2b0c40b23a0..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java +++ /dev/null @@ -1,847 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.client.AsyncCallback.RecoverCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class tests the bookie recovery admin functionality. - */ -public class BookieRecoveryTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(BookieRecoveryTest.class); - - // Object used for synchronizing async method calls - class SyncObject { - boolean value; - - public SyncObject() { - value = false; - } - } - - // Object used for implementing the Bookie RecoverCallback for this jUnit - // test. This verifies that the operation completed successfully. - class BookieRecoverCallback implements RecoverCallback { - boolean success = false; - @Override - public void recoverComplete(int rc, Object ctx) { - LOG.info("Recovered bookie operation completed with rc: " + rc); - success = rc == BKException.Code.OK; - SyncObject sync = (SyncObject) ctx; - synchronized (sync) { - sync.value = true; - sync.notify(); - } - } - } - - // Objects to use for this jUnit test. - DigestType digestType; - String ledgerManagerFactory; - SyncObject sync; - BookieRecoverCallback bookieRecoverCb; - BookKeeperAdmin bkAdmin; - - // Constructor - public BookieRecoveryTest() { - super(3); - - this.digestType = DigestType.CRC32; - this.ledgerManagerFactory = "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"; - LOG.info("Using ledger manager " + ledgerManagerFactory); - // set ledger manager - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseConf.setOpenFileLimit(200); // Limit the number of open files to avoid reaching the proc max - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - @Before - @Override - public void setUp() throws Exception { - // Set up the configuration properties needed. - baseClientConf.setBookieRecoveryDigestType(digestType); - baseClientConf.setBookieRecoveryPasswd("".getBytes()); - super.setUp(); - - sync = new SyncObject(); - bookieRecoverCb = new BookieRecoverCallback(); - ClientConfiguration adminConf = new ClientConfiguration(baseClientConf); - adminConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - bkAdmin = new BookKeeperAdmin(adminConf); - } - - @After - @Override - public void tearDown() throws Exception { - // Release any resources used by the BookieRecoveryTest instance. - if (bkAdmin != null){ - bkAdmin.close(); - } - super.tearDown(); - } - - /** - * Helper method to create a number of ledgers. - * - * @param numLedgers - * Number of ledgers to create - * @return List of LedgerHandles for each of the ledgers created - */ - private List createLedgers(int numLedgers) - throws BKException, IOException, InterruptedException { - return createLedgers(numLedgers, 3, 2); - } - - /** - * Helper method to create a number of ledgers. - * - * @param numLedgers - * Number of ledgers to create - * @param ensemble Ensemble size for ledgers - * @param quorum Quorum size for ledgers - * @return List of LedgerHandles for each of the ledgers created - */ - private List createLedgers(int numLedgers, int ensemble, int quorum) - throws BKException, IOException, - InterruptedException { - List lhs = new ArrayList(); - for (int i = 0; i < numLedgers; i++) { - lhs.add(bkc.createLedger(ensemble, quorum, - digestType, baseClientConf.getBookieRecoveryPasswd())); - } - return lhs; - } - - private List openLedgers(List oldLhs) - throws Exception { - List newLhs = new ArrayList(); - for (LedgerHandle oldLh : oldLhs) { - newLhs.add(bkc.openLedger(oldLh.getId(), digestType, baseClientConf.getBookieRecoveryPasswd())); - } - return newLhs; - } - - /** - * Helper method to write dummy ledger entries to all of the ledgers passed. - * - * @param numEntries - * Number of ledger entries to write for each ledger - * @param startEntryId - * The first entry Id we're expecting to write for each ledger - * @param lhs - * List of LedgerHandles for all ledgers to write entries to - * @throws BKException - * @throws InterruptedException - */ - private void writeEntriestoLedgers(int numEntries, long startEntryId, - List lhs) - throws BKException, InterruptedException { - for (LedgerHandle lh : lhs) { - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("LedgerId: " + lh.getId() + ", EntryId: " + (startEntryId + i)).getBytes()); - } - } - } - - private void closeLedgers(List lhs) throws BKException, InterruptedException { - for (LedgerHandle lh : lhs) { - lh.close(); - } - } - - /** - * Helper method to verify that we can read the recovered ledger entries. - * - * @param oldLhs - * Old Ledger Handles - * @param startEntryId - * Start Entry Id to read - * @param endEntryId - * End Entry Id to read - * @throws BKException - * @throws InterruptedException - */ - private void verifyRecoveredLedgers(List oldLhs, long startEntryId, long endEntryId) - throws BKException, InterruptedException { - // Get a set of LedgerHandles for all of the ledgers to verify - List lhs = new ArrayList(); - for (int i = 0; i < oldLhs.size(); i++) { - lhs.add(bkc.openLedger(oldLhs.get(i).getId(), digestType, baseClientConf.getBookieRecoveryPasswd())); - } - // Read the ledger entries to verify that they are all present and - // correct in the new bookie. - for (LedgerHandle lh : lhs) { - Enumeration entries = lh.readEntries(startEntryId, endEntryId); - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertTrue(new String(entry.getEntry()).equals("LedgerId: " + entry.getLedgerId() + ", EntryId: " - + entry.getEntryId())); - } - } - - } - - /** - * This tests the bookie recovery functionality with ensemble changes. - * We'll verify that: - * - bookie recovery should not affect ensemble change. - * - ensemble change should not erase changes made by recovery. - * - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-667} - */ - @Test - public void testMetadataConflictWithRecovery() throws Exception { - metadataConflictWithRecovery(bkc); - } - - @Test - public void testMetadataConflictWhenDelayingEnsembleChange() throws Exception { - ClientConfiguration newConf = new ClientConfiguration(baseClientConf); - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - newConf.setDelayEnsembleChange(true); - try (BookKeeper newBkc = new BookKeeper(newConf)) { - metadataConflictWithRecovery(newBkc); - } - } - - void metadataConflictWithRecovery(BookKeeper bkc) throws Exception { - int numEntries = 10; - byte[] data = "testMetadataConflictWithRecovery".getBytes(); - - LedgerHandle lh = bkc.createLedger(2, 2, digestType, baseClientConf.getBookieRecoveryPasswd()); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - BookieId bookieToKill = lh.getLedgerMetadata().getEnsembleAt(numEntries - 1).get(1); - killBookie(bookieToKill); - startNewBookie(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - bkAdmin.recoverBookieData(bookieToKill); - // fail another bookie to cause ensemble change again - bookieToKill = lh.getLedgerMetadata().getEnsembleAt(2 * numEntries - 1).get(1); - ServerConfiguration confOfKilledBookie = killBookie(bookieToKill); - startNewBookie(); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - // start the killed bookie again - startAndAddBookie(confOfKilledBookie); - - // all ensembles should be fully replicated since it is recovered - assertTrue("Not fully replicated", verifyFullyReplicated(lh, 3 * numEntries)); - lh.close(); - } - - /** - * This tests the asynchronous bookie recovery functionality by writing - * entries into 3 bookies, killing one bookie, starting up a new one to - * replace it, and then recovering the ledger entries from the killed bookie - * onto the new one. We'll verify that the entries stored on the killed - * bookie are properly copied over and restored onto the new one. - * - * @throws Exception - */ - @Test - public void testAsyncBookieRecoveryToSpecificBookie() throws Exception { - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers); - - // Write the entries for the ledgers with dummy values. - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - LOG.info("Finished writing all ledger entries so shutdown one of the bookies."); - BookieId bookieSrc = addressByIndex(0); - killBookie(0); - - // Startup a new bookie server - startNewBookie(); - - // Write some more entries for the ledgers so a new ensemble will be - // created for them. - writeEntriestoLedgers(numMsgs, 10, lhs); - - // Call the async recover bookie method. - // Initiate the sync object - sync.value = false; - bkAdmin.asyncRecoverBookieData(bookieSrc, bookieRecoverCb, sync); - - // Wait for the async method to complete. - synchronized (sync) { - while (!sync.value) { - sync.wait(); - } - assertTrue(bookieRecoverCb.success); - } - - // Verify the recovered ledger entries are okay. - verifyRecoveredLedgers(lhs, 0, 2 * numMsgs - 1); - } - - /** - * This tests the asynchronous bookie recovery functionality by writing - * entries into 3 bookies, killing one bookie, starting up a few new - * bookies, and then recovering the ledger entries from the killed bookie - * onto random available bookie servers. We'll verify that the entries - * stored on the killed bookie are properly copied over and restored onto - * the other bookies. - * - * @throws Exception - */ - @Test - public void testAsyncBookieRecoveryToRandomBookies() throws Exception { - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers); - - // Write the entries for the ledgers with dummy values. - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - LOG.info("Finished writing all ledger entries so shutdown one of the bookies."); - - BookieId bookieSrc = addressByIndex(0); - killBookie(0); - - // Startup three new bookie servers - for (int i = 0; i < 3; i++) { - startNewBookie(); - } - - // Write some more entries for the ledgers so a new ensemble will be - // created for them. - writeEntriestoLedgers(numMsgs, 10, lhs); - - // Call the async recover bookie method. - LOG.info("Now recover the data on the killed bookie (" + bookieSrc - + ") and replicate it to a random available one"); - // Initiate the sync object - sync.value = false; - bkAdmin.asyncRecoverBookieData(bookieSrc, bookieRecoverCb, sync); - - // Wait for the async method to complete. - synchronized (sync) { - while (!sync.value) { - sync.wait(); - } - assertTrue(bookieRecoverCb.success); - } - - // Verify the recovered ledger entries are okay. - verifyRecoveredLedgers(lhs, 0, 2 * numMsgs - 1); - } - - /** - * This tests the synchronous bookie recovery functionality by writing - * entries into 3 bookies, killing one bookie, starting up a new one to - * replace it, and then recovering the ledger entries from the killed bookie - * onto the new one. We'll verify that the entries stored on the killed - * bookie are properly copied over and restored onto the new one. - * - * @throws Exception - */ - @Test - public void testSyncBookieRecoveryToSpecificBookie() throws Exception { - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers); - - // Write the entries for the ledgers with dummy values. - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - LOG.info("Finished writing all ledger entries so shutdown one of the bookies."); - - BookieId bookieSrc = addressByIndex(0); - killBookie(0); - - // Startup a new bookie server - int newBookiePort = startNewBookie(); - - // Write some more entries for the ledgers so a new ensemble will be - //created for them. - writeEntriestoLedgers(numMsgs, 10, lhs); - - // Call the sync recover bookie method. - LOG.info("Now recover the data on the killed bookie (" + bookieSrc + ") and replicate it to other bookies"); - bkAdmin.recoverBookieData(bookieSrc); - - // Verify the recovered ledger entries are okay. - verifyRecoveredLedgers(lhs, 0, 2 * numMsgs - 1); - } - - /** - * This tests the synchronous bookie recovery functionality by writing - * entries into 3 bookies, killing one bookie, starting up a few new - * bookies, and then recovering the ledger entries from the killed bookie - * onto random available bookie servers. We'll verify that the entries - * stored on the killed bookie are properly copied over and restored onto - * the other bookies. - * - * @throws Exception - */ - @Test - public void testSyncBookieRecoveryToRandomBookies() throws Exception { - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers); - - // Write the entries for the ledgers with dummy values. - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - LOG.info("Finished writing all ledger entries so shutdown one of the bookies."); - - BookieId bookieSrc = addressByIndex(0); - killBookie(0); - - // Startup three new bookie servers - for (int i = 0; i < 3; i++) { - startNewBookie(); - } - - // Write some more entries for the ledgers so a new ensemble will be - // created for them. - writeEntriestoLedgers(numMsgs, 10, lhs); - - // Call the sync recover bookie method. - LOG.info("Now recover the data on the killed bookie (" + bookieSrc - + ") and replicate it to a random available one"); - bkAdmin.recoverBookieData(bookieSrc); - - // Verify the recovered ledger entries are okay. - verifyRecoveredLedgers(lhs, 0, 2 * numMsgs - 1); - } - - private static class ReplicationVerificationCallback implements ReadEntryCallback { - final CountDownLatch latch; - final AtomicLong numSuccess; - - ReplicationVerificationCallback(int numRequests) { - latch = new CountDownLatch(numRequests); - numSuccess = new AtomicLong(0); - } - - @Override - public void readEntryComplete(int rc, long ledgerId, long entryId, ByteBuf buffer, Object ctx) { - if (LOG.isDebugEnabled()) { - LOG.debug("Got " + rc + " for ledger " + ledgerId + " entry " + entryId + " from " + ctx); - } - if (rc == BKException.Code.OK) { - numSuccess.incrementAndGet(); - } - latch.countDown(); - } - - long await() throws InterruptedException { - if (!latch.await(60, TimeUnit.SECONDS)) { - LOG.warn("Didn't get all responses in verification"); - return 0; - } else { - return numSuccess.get(); - } - } - } - - private boolean verifyFullyReplicated(LedgerHandle lh, long untilEntry) throws Exception { - LedgerMetadata md = getLedgerMetadata(lh); - - Map> ensembles = md.getAllEnsembles(); - - HashMap ranges = new HashMap(); - ArrayList keyList = Collections.list( - Collections.enumeration(ensembles.keySet())); - Collections.sort(keyList); - for (int i = 0; i < keyList.size() - 1; i++) { - ranges.put(keyList.get(i), keyList.get(i + 1)); - } - ranges.put(keyList.get(keyList.size() - 1), untilEntry); - - for (Map.Entry> e : ensembles.entrySet()) { - int quorum = md.getAckQuorumSize(); - long startEntryId = e.getKey(); - long endEntryId = ranges.get(startEntryId); - long expectedSuccess = quorum * (endEntryId - startEntryId); - int numRequests = e.getValue().size() * ((int) (endEntryId - startEntryId)); - - ReplicationVerificationCallback cb = new ReplicationVerificationCallback(numRequests); - for (long i = startEntryId; i < endEntryId; i++) { - for (BookieId addr : e.getValue()) { - bkc.getBookieClient().readEntry(addr, lh.getId(), i, - cb, addr, BookieProtocol.FLAG_NONE); - } - } - - long numSuccess = cb.await(); - if (numSuccess < expectedSuccess) { - LOG.warn("Fragment not fully replicated ledgerId = " + lh.getId() - + " startEntryId = " + startEntryId - + " endEntryId = " + endEntryId - + " expectedSuccess = " + expectedSuccess - + " gotSuccess = " + numSuccess); - return false; - } - } - return true; - } - - // Object used for synchronizing async method calls - class SyncLedgerMetaObject { - boolean value; - int rc; - LedgerMetadata meta; - - public SyncLedgerMetaObject() { - value = false; - meta = null; - } - } - - private LedgerMetadata getLedgerMetadata(LedgerHandle lh) throws Exception { - return bkc.getLedgerManager().readLedgerMetadata(lh.getId()).get().getValue(); - } - - private boolean findDupesInEnsembles(List lhs) throws Exception { - long numDupes = 0; - for (LedgerHandle lh : lhs) { - LedgerMetadata md = getLedgerMetadata(lh); - for (Map.Entry> e : md.getAllEnsembles().entrySet()) { - HashSet set = new HashSet(); - long fragment = e.getKey(); - - for (BookieId addr : e.getValue()) { - if (set.contains(addr)) { - LOG.error("Dupe " + addr + " found in ensemble for fragment " + fragment - + " of ledger " + lh.getId()); - numDupes++; - } - set.add(addr); - } - } - } - return numDupes > 0; - } - - /** - * Test recoverying the closed ledgers when the failed bookie server is in the last ensemble. - */ - @Test - public void testBookieRecoveryOnClosedLedgers() throws Exception { - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers, numBookies, 2); - - // Write the entries for the ledgers with dummy values - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - closeLedgers(lhs); - - // Shutdown last bookie server in last ensemble - List lastEnsemble = lhs.get(0).getLedgerMetadata().getAllEnsembles() - .entrySet().iterator().next().getValue(); - BookieId bookieToKill = lastEnsemble.get(lastEnsemble.size() - 1); - killBookie(bookieToKill); - - // start a new bookie - startNewBookie(); - - LOG.info("Now recover the data on the killed bookie (" + bookieToKill - + ") and replicate it to a random available one"); - - bkAdmin.recoverBookieData(bookieToKill); - for (LedgerHandle lh : lhs) { - assertTrue("Not fully replicated", verifyFullyReplicated(lh, numMsgs)); - lh.close(); - } - } - - @Test - public void testBookieRecoveryOnOpenedLedgers() throws Exception { - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers, numBookies, 2); - - // Write the entries for the ledgers with dummy values - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - List lastEnsemble = lhs.get(0).getLedgerMetadata().getAllEnsembles() - .entrySet().iterator().next().getValue(); - BookieId bookieToKill = lastEnsemble.get(lastEnsemble.size() - 1); - killBookie(bookieToKill); - - // start a new bookie - startNewBookie(); - - LOG.info("Now recover the data on the killed bookie (" + bookieToKill - + ") and replicate it to a random available one"); - - bkAdmin.recoverBookieData(bookieToKill); - - for (LedgerHandle lh : lhs) { - assertTrue("Not fully replicated", verifyFullyReplicated(lh, numMsgs)); - } - - try { - // we can't write entries - writeEntriestoLedgers(numMsgs, 0, lhs); - fail("should not reach here"); - } catch (Exception e) { - } - } - - @Test - public void testBookieRecoveryOnInRecoveryLedger() throws Exception { - int numMsgs = 10; - // Create the ledgers - int numLedgers = 1; - List lhs = createLedgers(numLedgers, 2, 2); - - // Write the entries for the ledgers with dummy values - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - List lastEnsemble = lhs.get(0).getLedgerMetadata().getAllEnsembles() - .entrySet().iterator().next().getValue(); - // removed bookie - BookieId bookieToKill = lastEnsemble.get(0); - killBookie(bookieToKill); - // temp failure - BookieId bookieToKill2 = lastEnsemble.get(1); - ServerConfiguration conf2 = killBookie(bookieToKill2); - - // start a new bookie - startNewBookie(); - - // open these ledgers - for (LedgerHandle oldLh : lhs) { - try { - bkc.openLedger(oldLh.getId(), digestType, baseClientConf.getBookieRecoveryPasswd()); - fail("Should have thrown exception"); - } catch (Exception e) { - } - } - - try { - bkAdmin.recoverBookieData(bookieToKill); - fail("Should have thrown exception"); - } catch (BKException.BKLedgerRecoveryException bke) { - // correct behaviour - } - - // restart failed bookie - startAndAddBookie(conf2); - - // recover them - bkAdmin.recoverBookieData(bookieToKill); - - for (LedgerHandle lh : lhs) { - assertTrue("Not fully replicated", verifyFullyReplicated(lh, numMsgs)); - } - - // open ledgers to read metadata - List newLhs = openLedgers(lhs); - for (LedgerHandle newLh : newLhs) { - // first ensemble should contains bookieToKill2 and not contain bookieToKill - Map.Entry> entry = - newLh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next(); - assertFalse(entry.getValue().contains(bookieToKill)); - assertTrue(entry.getValue().contains(bookieToKill2)); - } - - } - - @Test - public void testAsyncBookieRecoveryToRandomBookiesNotEnoughBookies() throws Exception { - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers, numBookies, 2); - - // Write the entries for the ledgers with dummy values. - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - LOG.info("Finished writing all ledger entries so shutdown one of the bookies."); - - BookieId bookieSrc = addressByIndex(0); - killBookie(0); - - // Call the async recover bookie method. - LOG.info("Now recover the data on the killed bookie (" + bookieSrc - + ") and replicate it to a random available one"); - // Initiate the sync object - sync.value = false; - try { - bkAdmin.recoverBookieData(bookieSrc); - fail("Should have thrown exception"); - } catch (BKException.BKLedgerRecoveryException bke) { - // correct behaviour - } - } - - @Test - public void testSyncBookieRecoveryToRandomBookiesCheckForDupes() throws Exception { - Random r = new Random(); - - // Create the ledgers - int numLedgers = 3; - List lhs = createLedgers(numLedgers, numBookies, 2); - - // Write the entries for the ledgers with dummy values. - int numMsgs = 10; - writeEntriestoLedgers(numMsgs, 0, lhs); - - // Shutdown the first bookie server - LOG.info("Finished writing all ledger entries so shutdown one of the bookies."); - int removeIndex = r.nextInt(bookieCount()); - BookieId bookieSrc = addressByIndex(removeIndex); - killBookie(removeIndex); - - // Startup new bookie server - startNewBookie(); - - // Write some more entries for the ledgers so a new ensemble will be - // created for them. - writeEntriestoLedgers(numMsgs, numMsgs, lhs); - - // Call the async recover bookie method. - LOG.info("Now recover the data on the killed bookie (" + bookieSrc - + ") and replicate it to a random available one"); - // Initiate the sync object - sync.value = false; - bkAdmin.recoverBookieData(bookieSrc); - - assertFalse("Dupes exist in ensembles", findDupesInEnsembles(lhs)); - - // Write some more entries to ensure fencing hasn't broken stuff - writeEntriestoLedgers(numMsgs, numMsgs * 2, lhs); - - for (LedgerHandle lh : lhs) { - assertTrue("Not fully replicated", verifyFullyReplicated(lh, numMsgs * 3)); - lh.close(); - } - } - - @Test - public void recoverWithoutPasswordInConf() throws Exception { - byte[] passwdCorrect = "AAAAAA".getBytes(); - byte[] passwdBad = "BBBBBB".getBytes(); - DigestType digestCorrect = digestType; - - LedgerHandle lh = bkc.createLedger(3, 2, digestCorrect, passwdCorrect); - long ledgerId = lh.getId(); - for (int i = 0; i < 100; i++) { - lh.addEntry("foobar".getBytes()); - } - lh.close(); - - BookieId bookieSrc = addressByIndex(0); - killBookie(0); - - startNewBookie(); - - // Check that entries are missing - lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect); - assertFalse("Should be entries missing", verifyFullyReplicated(lh, 100)); - lh.close(); - - // Try to recover with bad password in conf - // This is fine, because it only falls back to the configured - // password if the password info is missing from the metadata - ClientConfiguration adminConf = new ClientConfiguration(); - adminConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - adminConf.setBookieRecoveryDigestType(digestCorrect); - adminConf.setBookieRecoveryPasswd(passwdBad); - setMetastoreImplClass(adminConf); - - BookKeeperAdmin bka = new BookKeeperAdmin(adminConf); - bka.recoverBookieData(bookieSrc); - bka.close(); - - lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect); - assertTrue("Should be back to fully replication", verifyFullyReplicated(lh, 100)); - lh.close(); - - bookieSrc = addressByIndex(0); - killBookie(0); - startNewBookie(); - - // Check that entries are missing - lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect); - assertFalse("Should be entries missing", verifyFullyReplicated(lh, 100)); - lh.close(); - - // Try to recover with no password in conf - adminConf = new ClientConfiguration(); - adminConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - setMetastoreImplClass(adminConf); - - bka = new BookKeeperAdmin(adminConf); - bka.recoverBookieData(bookieSrc); - bka.close(); - - lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect); - assertTrue("Should be back to fully replication", verifyFullyReplicated(lh, 100)); - lh.close(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryUseIOThreadTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryUseIOThreadTest.java deleted file mode 100644 index 3bf87f4cf17..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryUseIOThreadTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Tests for Bookie recovery use IO threads. - */ -public class BookieRecoveryUseIOThreadTest extends BookKeeperClusterTestCase { - - public BookieRecoveryUseIOThreadTest() { - super(1); - } - - @Override - public void setUp() throws Exception { - baseConf.setNumAddWorkerThreads(0); - baseConf.setNumReadWorkerThreads(0); - baseConf.setNumHighPriorityWorkerThreads(0); - super.setUp(); - } - - @Test - public void testRecoveryClosedLedger() throws BKException, IOException, InterruptedException { - // test the v2 protocol when using IO thread to handle the request - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setUseV2WireProtocol(true); - AtomicInteger finalRc = new AtomicInteger(Integer.MAX_VALUE); - CountDownLatch latch = new CountDownLatch(1); - try (BookKeeper bkc = new BookKeeper(conf)) { - bkc.asyncCreateLedger(1, 1, BookKeeper.DigestType.CRC32, "".getBytes(), - new AsyncCallback.CreateCallback() { - @Override - public void createComplete(int rc, LedgerHandle lh, Object ctx) { - lh.asyncAddEntry("hello".getBytes(), new AsyncCallback.AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - if (rc == BKException.Code.OK) { - bkc.asyncOpenLedger(lh.ledgerId, BookKeeper.DigestType.CRC32, "".getBytes(), - new AsyncCallback.OpenCallback() { - @Override - public void openComplete(int rc, LedgerHandle lh, Object ctx) { - finalRc.set(rc); - latch.countDown(); - } - }, null); - } - } - }, null); - } - }, null); - latch.await(); - } - Assert.assertEquals(finalRc.get(), org.apache.bookkeeper.client.api.BKException.Code.OK); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgerTest.java deleted file mode 100644 index 52d1326af33..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgerTest.java +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.BookKeeperClientStats.ADD_OP; -import static org.apache.bookkeeper.client.BookKeeperClientStats.ADD_OP_UR; -import static org.apache.bookkeeper.client.BookKeeperClientStats.CLIENT_SCOPE; -import static org.apache.bookkeeper.client.BookKeeperClientStats.READ_OP_DM; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import io.netty.buffer.AbstractByteBufAllocator; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.IOException; -import java.net.URI; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BKException.BKLedgerClosedException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteAdvHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerMetadataSerDe; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.LongHierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.replication.ReplicationTestUtil; -import org.apache.bookkeeper.replication.ReplicationWorker; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.commons.lang3.tuple.Pair; -import org.awaitility.Awaitility; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Testing ledger write entry cases. - */ -@RunWith(Parameterized.class) -public class BookieWriteLedgerTest extends - BookKeeperClusterTestCase implements AddCallback { - - private static final Logger LOG = LoggerFactory - .getLogger(BookieWriteLedgerTest.class); - - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { - { true, true }, { true, false }, { false, true }, { false, false } - }); - } - - @Parameterized.Parameter(0) - public boolean useV2; - - @Parameterized.Parameter(1) - public boolean writeJournal; - - byte[] ledgerPassword = "aaa".getBytes(); - LedgerHandle lh, lh2; - Enumeration ls; - - // test related variables - int numEntriesToWrite = 100; - int maxInt = Integer.MAX_VALUE; - Random rng; // Random Number Generator - ArrayList entries1; // generated entries - ArrayList entries2; // generated entries - - private final DigestType digestType; - - private static class SyncObj { - volatile int counter; - volatile int rc; - - public SyncObj() { - counter = 0; - } - } - - @Override - @Before - public void setUp() throws Exception { - baseConf.setJournalWriteData(writeJournal); - baseClientConf.setUseV2WireProtocol(useV2); - - super.setUp(); - rng = new Random(0); // Initialize the Random - // Number Generator - entries1 = new ArrayList(); // initialize the entries list - entries2 = new ArrayList(); // initialize the entries list - } - - public BookieWriteLedgerTest() { - super(5, 180); - this.digestType = DigestType.CRC32; - String ledgerManagerFactory = "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"; - // set ledger manager - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - /* - * 'testLedgerCreateAdvWithLedgerIdInLoop2' testcase relies on skipListSizeLimit, - * so setting it to some small value for making that testcase lite. - */ - baseConf.setSkipListSizeLimit(4 * 1024 * 1024); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - /** - * Verify write when few bookie failures in last ensemble and forcing - * ensemble reformation. - */ - @Test - public void testWithMultipleBookieFailuresInLastEnsemble() throws Exception { - // Create a ledger - lh = bkc.createLedger(5, 4, digestType, ledgerPassword); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - // Start three more bookies - startNewBookie(); - startNewBookie(); - startNewBookie(); - - // Shutdown three bookies in the last ensemble and continue writing - List ensemble = lh.getLedgerMetadata() - .getAllEnsembles().entrySet().iterator().next().getValue(); - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - killBookie(ensemble.get(2)); - - int i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 50; - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - readEntries(lh, entries1); - lh.close(); - } - - /** - * Verify write and Read durability stats. - */ - @Test - public void testWriteAndReadStats() throws Exception { - // Create a ledger - lh = bkc.createLedger(3, 3, 2, digestType, ledgerPassword); - - // write-batch-1 - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - assertTrue( - "Stats should have captured a new writes", - bkc.getTestStatsProvider().getOpStatsLogger( - CLIENT_SCOPE + "." + ADD_OP) - .getSuccessCount() > 0); - - CountDownLatch sleepLatch1 = new CountDownLatch(1); - CountDownLatch sleepLatch2 = new CountDownLatch(1); - List ensemble = lh.getLedgerMetadata() - .getAllEnsembles().entrySet().iterator().next().getValue(); - - sleepBookie(ensemble.get(0), sleepLatch1); - - int i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 50; - - // write-batch-2 - - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - - // Let the second bookie go to sleep. This forces write timeout and ensemble change - // Which will be enough time to receive delayed write failures on the write-batch-2 - - sleepBookie(ensemble.get(1), sleepLatch2); - i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 50; - - // write-batch-3 - - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - - assertTrue( - "Stats should have captured a new UnderReplication during write", - bkc.getTestStatsProvider().getCounter( - CLIENT_SCOPE + "." + ADD_OP_UR) - .get() > 0); - - sleepLatch1.countDown(); - sleepLatch2.countDown(); - - // Replace the bookie with a fake bookie - ServerConfiguration conf = killBookie(ensemble.get(0)); - BookieWriteLedgerTest.CorruptReadBookie corruptBookie = new BookieWriteLedgerTest.CorruptReadBookie(conf); - startAndAddBookie(conf, corruptBookie); - - i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 50; - - // write-batch-4 - - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - - readEntries(lh, entries1); - assertTrue( - "Stats should have captured DigestMismatch on Read", - bkc.getTestStatsProvider().getCounter( - CLIENT_SCOPE + "." + READ_OP_DM) - .get() > 0); - lh.close(); - } - /** - * Verty delayedWriteError causes ensemble changes. - */ - @Test - public void testDelayedWriteEnsembleChange() throws Exception { - // Create a ledger - lh = bkc.createLedger(3, 3, 2, digestType, ledgerPassword); - baseClientConf.setAddEntryTimeout(1); - - int numEntriesToWrite = 10; - // write-batch-1 - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - - CountDownLatch sleepLatch1 = new CountDownLatch(1); - - // get bookie at index-0 - BookieId bookie1 = lh.getCurrentEnsemble().get(0); - sleepBookie(bookie1, sleepLatch1); - - int i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 10; - - // write-batch-2 - - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - // Sleep to receive delayed error on the write directed to the sleeping bookie - Thread.sleep(baseClientConf.getAddEntryTimeout() * 1000 * 2); - assertTrue( - "Stats should have captured a new UnderReplication during write", - bkc.getTestStatsProvider().getCounter( - CLIENT_SCOPE + "." + ADD_OP_UR) - .get() > 0); - - i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 10; - - // write-batch-3 - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - - sleepLatch1.countDown(); - // get the bookie at index-0 again, this must be different. - BookieId bookie2 = lh.getCurrentEnsemble().get(0); - - assertFalse( - "Delayed write error must have forced ensemble change", - bookie1.equals(bookie2)); - lh.close(); - } - /** - * Verify the functionality Ledgers with different digests. - * - * @throws Exception - */ - @Test - public void testLedgerDigestTest() throws Exception { - for (DigestType type: DigestType.values()) { - lh = bkc.createLedger(5, 3, 2, type, ledgerPassword); - - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(entry.array()); - } - - readEntries(lh, entries1); - - long lid = lh.getId(); - lh.close(); - bkc.deleteLedger(lid); - entries1.clear(); - } - } - - /** - * Verify the functionality of Advanced Ledger which returns - * LedgerHandleAdv. LedgerHandleAdv takes entryId for addEntry, and let - * user manage entryId allocation. - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdv() throws Exception { - // Create a ledger - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(i, entry.array()); - } - // Start one more bookies - startNewBookie(); - - // Shutdown one bookie in the last ensemble and continue writing - List ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next() - .getValue(); - killBookie(ensemble.get(0)); - - int i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 50; - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(i, entry.array()); - } - - readEntries(lh, entries1); - lh.close(); - } - - /** - * Verify that attempts to use addEntry() variant that does not require specifying entry id - * on LedgerHandleAdv results in error. - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdvAndWriteNonAdv() throws Exception { - long ledgerId = 0xABCDEF; - lh = bkc.createLedgerAdv(ledgerId, 3, 3, 2, digestType, ledgerPassword, null); - - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - try { - lh.addEntry(entry.array()); - fail("expected IllegalOpException"); - } catch (BKException.BKIllegalOpException e) { - // pass, expected - } finally { - lh.close(); - bkc.deleteLedger(ledgerId); - } - } - - /** - * Verify that LedgerHandleAdv cannnot handle addEntry without the entryId. - * - * @throws Exception - */ - @Test - public void testNoAddEntryLedgerCreateAdv() throws Exception { - - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - assertTrue(lh instanceof LedgerHandleAdv); - - try { - lh.addEntry(entry.array()); - fail("using LedgerHandleAdv addEntry without entryId is forbidden"); - } catch (BKException e) { - assertEquals(e.getCode(), BKException.Code.IllegalOpException); - } - - try { - lh.addEntry(entry.array(), 0, 4); - fail("using LedgerHandleAdv addEntry without entryId is forbidden"); - } catch (BKException e) { - assertEquals(e.getCode(), BKException.Code.IllegalOpException); - } - - try { - CompletableFuture done = new CompletableFuture<>(); - lh.asyncAddEntry(Unpooled.wrappedBuffer(entry.array()), - (int rc, LedgerHandle lh1, long entryId, Object ctx) -> { - SyncCallbackUtils.finish(rc, null, done); - }, null); - done.get(); - } catch (ExecutionException ee) { - assertTrue(ee.getCause() instanceof BKException); - BKException e = (BKException) ee.getCause(); - assertEquals(e.getCode(), BKException.Code.IllegalOpException); - } - - try { - CompletableFuture done = new CompletableFuture<>(); - lh.asyncAddEntry(entry.array(), - (int rc, LedgerHandle lh1, long entryId, Object ctx) -> { - SyncCallbackUtils.finish(rc, null, done); - }, null); - done.get(); - } catch (ExecutionException ee) { - assertTrue(ee.getCause() instanceof BKException); - BKException e = (BKException) ee.getCause(); - assertEquals(e.getCode(), BKException.Code.IllegalOpException); - } - - try { - CompletableFuture done = new CompletableFuture<>(); - lh.asyncAddEntry(entry.array(), 0, 4, - (int rc, LedgerHandle lh1, long entryId, Object ctx) -> { - SyncCallbackUtils.finish(rc, null, done); - }, null); - done.get(); - } catch (ExecutionException ee) { - assertTrue(ee.getCause() instanceof BKException); - BKException e = (BKException) ee.getCause(); - assertEquals(e.getCode(), BKException.Code.IllegalOpException); - } - lh.close(); - } - - /** - * Verify the functionality of Advanced Ledger which accepts ledgerId as input and returns - * LedgerHandleAdv. LedgerHandleAdv takes entryId for addEntry, and let - * user manage entryId allocation. - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdvWithLedgerId() throws Exception { - // Create a ledger - long ledgerId = 0xABCDEF; - lh = bkc.createLedgerAdv(ledgerId, 5, 3, 2, digestType, ledgerPassword, null); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(i, entry.array()); - } - // Start one more bookies - startNewBookie(); - - // Shutdown one bookie in the last ensemble and continue writing - List ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next() - .getValue(); - killBookie(ensemble.get(0)); - - int i = numEntriesToWrite; - numEntriesToWrite = numEntriesToWrite + 50; - for (; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(i, entry.array()); - } - - readEntries(lh, entries1); - lh.close(); - bkc.deleteLedger(ledgerId); - } - - /** - * Verify the functionality of Ledger create which accepts customMetadata as input. - * Also verifies that the data written is read back properly. - * - * @throws Exception - */ - @Test - public void testLedgerCreateWithCustomMetadata() throws Exception { - // Create a ledger - long ledgerId; - int maxLedgers = 10; - for (int i = 0; i < maxLedgers; i++) { - Map inputCustomMetadataMap = new HashMap(); - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - // each ledger has different number of key, value pairs. - for (int j = 0; j < i; j++) { - inputCustomMetadataMap.put("key" + j, UUID.randomUUID().toString().getBytes()); - } - - if (i < maxLedgers / 2) { - // 0 to 4 test with createLedger interface - lh = bkc.createLedger(5, 3, 2, digestType, ledgerPassword, inputCustomMetadataMap); - ledgerId = lh.getId(); - lh.addEntry(entry.array()); - } else { - // 5 to 9 test with createLedgerAdv interface - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword, inputCustomMetadataMap); - ledgerId = lh.getId(); - lh.addEntry(0, entry.array()); - } - lh.close(); - - // now reopen the ledger; this should fetch all the metadata stored on zk - // and the customMetadata written and read should match - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - Map outputCustomMetadataMap = lh.getCustomMetadata(); - assertTrue("Can't retrieve proper Custom Data", - areByteArrayValMapsEqual(inputCustomMetadataMap, outputCustomMetadataMap)); - lh.close(); - bkc.deleteLedger(ledgerId); - } - } - - /** - * Routine to compare two {@code Map}; Since the values in the map are {@code byte[]}, we can't use - * {@code Map.equals}. - * @param first - * The first map - * @param second - * The second map to compare with - * @return true if the 2 maps contain the exact set of {@code } pairs. - */ - public static boolean areByteArrayValMapsEqual(Map first, Map second) { - if (first == null && second == null) { - return true; - } - - // above check confirms that both are not null; - // if one is null the other isn't; so they must - // be different - if (first == null || second == null) { - return false; - } - - if (first.size() != second.size()) { - return false; - } - for (Map.Entry entry : first.entrySet()) { - if (!Arrays.equals(entry.getValue(), second.get(entry.getKey()))) { - return false; - } - } - return true; - } - - /* - * Verify the functionality of Advanced Ledger which accepts ledgerId as - * input and returns LedgerHandleAdv. LedgerHandleAdv takes entryId for - * addEntry, and let user manage entryId allocation. - * This testcase is mainly added for covering missing code coverage branches - * in LedgerHandleAdv - * - * @throws Exception - */ - @Test - public void testLedgerHandleAdvFunctionality() throws Exception { - // Create a ledger - long ledgerId = 0xABCDEF; - lh = bkc.createLedgerAdv(ledgerId, 5, 3, 2, digestType, ledgerPassword, null); - numEntriesToWrite = 3; - - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries1.add(entry.array()); - lh.addEntry(0, entry.array()); - - // here asyncAddEntry(final long entryId, final byte[] data, final - // AddCallback cb, final Object ctx) method is - // called which is not covered in any other testcase - entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries1.add(entry.array()); - CountDownLatch latch = new CountDownLatch(1); - final int[] returnedRC = new int[1]; - lh.asyncAddEntry(1, entry.array(), new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - returnedRC[0] = rc; - latch.countDown(); - } - }, latch); - latch.await(); - assertTrue("Returned code is expected to be OK", returnedRC[0] == BKException.Code.OK); - - // here addEntry is called with incorrect offset and length - entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - try { - lh.addEntry(2, entry.array(), -3, 9); - fail("AddEntry is called with negative offset and incorrect length," - + "so it is expected to throw RuntimeException/IndexOutOfBoundsException"); - } catch (RuntimeException exception) { - // expected RuntimeException/IndexOutOfBoundsException - } - - // here addEntry is called with corrected offset and length and it is - // supposed to succeed - entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries1.add(entry.array()); - lh.addEntry(2, entry.array()); - - // LedgerHandle is closed for write - lh.close(); - - // here addEntry is called even after the close of the LedgerHandle, so - // it is expected to throw exception - entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries1.add(entry.array()); - try { - lh.addEntry(3, entry.array()); - fail("AddEntry is called after the close of LedgerHandle," - + "so it is expected to throw BKLedgerClosedException"); - } catch (BKLedgerClosedException exception) { - } - - readEntries(lh, entries1); - bkc.deleteLedger(ledgerId); - } - - /** - * In a loop create/write/delete the ledger with same ledgerId through - * the functionality of Advanced Ledger which accepts ledgerId as input. - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdvWithLedgerIdInLoop() throws Exception { - int ledgerCount = 40; - - long maxId = 9999999999L; - if (baseConf.getLedgerManagerFactoryClass().equals(LongHierarchicalLedgerManagerFactory.class)) { - // since LongHierarchicalLedgerManager supports ledgerIds of decimal length upto 19 digits but other - // LedgerManagers only upto 10 decimals - maxId = Long.MAX_VALUE; - } - - rng.longs(ledgerCount, 0, maxId) // generate a stream of ledger ids - .mapToObj(ledgerId -> { // create a ledger for each ledger id - LOG.info("Creating adv ledger with id {}", ledgerId); - return bkc.newCreateLedgerOp() - .withEnsembleSize(1).withWriteQuorumSize(1).withAckQuorumSize(1) - .withDigestType(org.apache.bookkeeper.client.api.DigestType.CRC32) - .withPassword(ledgerPassword).makeAdv().withLedgerId(ledgerId) - .execute() - .thenCompose(writer -> { // Add entries to ledger when created - LOG.info("Writing stream of {} entries to {}", - numEntriesToWrite, ledgerId); - List entries = rng.ints(numEntriesToWrite, 0, maxInt) - .mapToObj(i -> { - ByteBuf entry = Unpooled.buffer(4); - entry.retain(); - entry.writeInt(i); - return entry; - }) - .collect(Collectors.toList()); - CompletableFuture lastRequest = null; - int i = 0; - for (ByteBuf entry : entries) { - long entryId = i++; - LOG.info("Writing {}:{} as {}", - ledgerId, entryId, entry.slice().readInt()); - lastRequest = writer.writeAsync(entryId, entry); - } - return lastRequest - .thenApply(___ -> Pair.of(writer, entries)); - }); - }) - .parallel().map(CompletableFuture::join) // wait for all creations and adds in parallel - .forEach(e -> { // check that each set of adds succeeded - try { - WriteAdvHandle handle = e.getLeft(); - List entries = e.getRight(); - // Read and verify - LOG.info("Read entries for ledger: {}", handle.getId()); - readEntries(handle, entries); - entries.forEach(ByteBuf::release); - handle.close(); - bkc.deleteLedger(handle.getId()); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - Assert.fail("Test interrupted"); - } catch (Exception ex) { - LOG.info("Readback failed with exception", ex); - Assert.fail("Readback failed " + ex.getMessage()); - } - }); - } - - /** - * In a loop create/write/read/delete the ledger with ledgerId through the - * functionality of Advanced Ledger which accepts ledgerId as input. - * In this testcase (other testcases don't cover these conditions, hence new - * testcase is added), we create entries which are greater than - * SKIP_LIST_MAX_ALLOC_ENTRY size and tried to addEntries so that the total - * length of data written in this testcase is much greater than - * SKIP_LIST_SIZE_LIMIT, so that entries will be flushed from EntryMemTable - * to persistent storage - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdvWithLedgerIdInLoop2() throws Exception { - - assertTrue("Here we are expecting Bookies are configured to use SortedLedgerStorage", - baseConf.getSortedLedgerStorageEnabled()); - - long ledgerId; - int ledgerCount = 10; - - List> entryList = new ArrayList>(); - LedgerHandle[] lhArray = new LedgerHandle[ledgerCount]; - long skipListSizeLimit = baseConf.getSkipListSizeLimit(); - int skipListArenaMaxAllocSize = baseConf.getSkipListArenaMaxAllocSize(); - - List tmpEntry; - for (int lc = 0; lc < ledgerCount; lc++) { - tmpEntry = new ArrayList(); - - ledgerId = rng.nextLong(); - ledgerId &= Long.MAX_VALUE; - if (!baseConf.getLedgerManagerFactoryClass().equals(LongHierarchicalLedgerManagerFactory.class)) { - // since LongHierarchicalLedgerManager supports ledgerIds of - // decimal length upto 19 digits but other - // LedgerManagers only upto 10 decimals - ledgerId %= 9999999999L; - } - - if (LOG.isDebugEnabled()) { - LOG.debug("Iteration: {} LedgerId: {}", lc, ledgerId); - } - lh = bkc.createLedgerAdv(ledgerId, 5, 3, 2, digestType, ledgerPassword, null); - lhArray[lc] = lh; - - long ledgerLength = 0; - int i = 0; - while (ledgerLength < ((4 * skipListSizeLimit) / ledgerCount)) { - int length; - if (rng.nextBoolean()) { - length = Math.abs(rng.nextInt()) % (skipListArenaMaxAllocSize); - } else { - // here we want length to be random no. in the range of skipListArenaMaxAllocSize and - // 4*skipListArenaMaxAllocSize - length = (Math.abs(rng.nextInt()) % (skipListArenaMaxAllocSize * 3)) + skipListArenaMaxAllocSize; - } - byte[] data = new byte[length]; - rng.nextBytes(data); - tmpEntry.add(data); - lh.addEntry(i, data); - ledgerLength += length; - i++; - } - entryList.add(tmpEntry); - } - for (int lc = 0; lc < ledgerCount; lc++) { - // Read and verify - long lid = lhArray[lc].getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("readEntries for lc: {} ledgerId: {} ", lc, lhArray[lc].getId()); - } - readEntriesAndValidateDataArray(lhArray[lc], entryList.get(lc)); - lhArray[lc].close(); - bkc.deleteLedger(lid); - } - } - - /** - * Verify asynchronous writing when few bookie failures in last ensemble. - */ - @Test - public void testAsyncWritesWithMultipleFailuresInLastEnsemble() - throws Exception { - // Create ledgers - lh = bkc.createLedger(5, 4, digestType, ledgerPassword); - lh2 = bkc.createLedger(5, 4, digestType, ledgerPassword); - - LOG.info("Ledger ID-1: " + lh.getId()); - LOG.info("Ledger ID-2: " + lh2.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - entries2.add(entry.array()); - lh.addEntry(entry.array()); - lh2.addEntry(entry.array()); - } - // Start three more bookies - startNewBookie(); - startNewBookie(); - startNewBookie(); - - // Shutdown three bookies in the last ensemble and continue writing - List ensemble = lh.getLedgerMetadata() - .getAllEnsembles().entrySet().iterator().next().getValue(); - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - killBookie(ensemble.get(2)); - - // adding one more entry to both the ledgers async after multiple bookie - // failures. This will do asynchronously modifying the ledger metadata - // simultaneously. - numEntriesToWrite++; - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries1.add(entry.array()); - entries2.add(entry.array()); - - SyncObj syncObj1 = new SyncObj(); - SyncObj syncObj2 = new SyncObj(); - lh.asyncAddEntry(entry.array(), this, syncObj1); - lh2.asyncAddEntry(entry.array(), this, syncObj2); - - // wait for all entries to be acknowledged for the first ledger - synchronized (syncObj1) { - while (syncObj1.counter < 1) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + syncObj1.counter); - } - syncObj1.wait(); - } - assertEquals(BKException.Code.OK, syncObj1.rc); - } - // wait for all entries to be acknowledged for the second ledger - synchronized (syncObj2) { - while (syncObj2.counter < 1) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + syncObj2.counter); - } - syncObj2.wait(); - } - assertEquals(BKException.Code.OK, syncObj2.rc); - } - - // reading ledger till the last entry - readEntries(lh, entries1); - readEntries(lh2, entries2); - lh.close(); - lh2.close(); - } - - /** - * Verify Advanced asynchronous writing with entryIds in reverse order. - */ - @Test - public void testLedgerCreateAdvWithAsyncWritesWithBookieFailures() throws Exception { - // Create ledgers - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - lh2 = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - - LOG.info("Ledger ID-1: " + lh.getId()); - LOG.info("Ledger ID-2: " + lh2.getId()); - SyncObj syncObj1 = new SyncObj(); - SyncObj syncObj2 = new SyncObj(); - for (int i = numEntriesToWrite - 1; i >= 0; i--) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - try { - entries1.add(0, entry.array()); - entries2.add(0, entry.array()); - } catch (Exception e) { - e.printStackTrace(); - } - lh.asyncAddEntry(i, entry.array(), 0, entry.capacity(), this, syncObj1); - lh2.asyncAddEntry(i, entry.array(), 0, entry.capacity(), this, syncObj2); - } - // Start One more bookie and shutdown one from last ensemble before reading - startNewBookie(); - List ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next() - .getValue(); - killBookie(ensemble.get(0)); - - // Wait for all entries to be acknowledged for the first ledger - synchronized (syncObj1) { - while (syncObj1.counter < numEntriesToWrite) { - syncObj1.wait(); - } - assertEquals(BKException.Code.OK, syncObj1.rc); - } - // Wait for all entries to be acknowledged for the second ledger - synchronized (syncObj2) { - while (syncObj2.counter < numEntriesToWrite) { - syncObj2.wait(); - } - assertEquals(BKException.Code.OK, syncObj2.rc); - } - - // Reading ledger till the last entry - readEntries(lh, entries1); - readEntries(lh2, entries2); - lh.close(); - lh2.close(); - } - - /** - * LedgerHandleAdv out of order writers with ensemble changes. - * Verify that entry that was written to old ensemble will be - * written to new enseble too after ensemble change. - * - * @throws Exception - */ - @Test - public void testLedgerHandleAdvOutOfOrderWriteAndFrocedEnsembleChange() throws Exception { - // Create a ledger - long ledgerId = 0xABCDEF; - SyncObj syncObj1 = new SyncObj(); - ByteBuffer entry; - lh = bkc.createLedgerAdv(ledgerId, 3, 3, 3, digestType, ledgerPassword, null); - entry = ByteBuffer.allocate(4); - // Add entries 0-4 - for (int i = 0; i < 5; i++) { - entry.rewind(); - entry.putInt(rng.nextInt(maxInt)); - lh.addEntry(i, entry.array()); - } - - // Add 10 as Async Entry, which goes to first ensemble - ByteBuffer entry1 = ByteBuffer.allocate(4); - entry1.putInt(rng.nextInt(maxInt)); - lh.asyncAddEntry(10, entry1.array(), 0, entry1.capacity(), this, syncObj1); - - // Make sure entry-10 goes to the bookies and gets response. - java.util.Queue myPendingAddOps = lh.getPendingAddOps(); - PendingAddOp addOp = null; - boolean pendingAddOpReceived = false; - - while (!pendingAddOpReceived) { - addOp = myPendingAddOps.peek(); - if (addOp.entryId == 10 && addOp.completed) { - pendingAddOpReceived = true; - } else { - Thread.sleep(1000); - } - } - - CountDownLatch sleepLatch1 = new CountDownLatch(1); - List ensemble; - - ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next().getValue(); - - // Put all 3 bookies to sleep and start 3 new ones - sleepBookie(ensemble.get(0), sleepLatch1); - sleepBookie(ensemble.get(1), sleepLatch1); - sleepBookie(ensemble.get(2), sleepLatch1); - startNewBookie(); - startNewBookie(); - startNewBookie(); - - // Original bookies are in sleep, new bookies added. - // Now add entries 5-9 which forces ensemble changes - // So at this point entries 0-4, 10 went to first - // ensemble, 5-9 will go to new ensemble. - for (int i = 5; i < 10; i++) { - entry.rewind(); - entry.putInt(rng.nextInt(maxInt)); - lh.addEntry(i, entry.array()); - } - - // Wakeup all 3 bookies that went to sleep - sleepLatch1.countDown(); - - // Wait for all entries to be acknowledged for the first ledger - synchronized (syncObj1) { - while (syncObj1.counter < 1) { - syncObj1.wait(); - } - assertEquals(BKException.Code.OK, syncObj1.rc); - } - - // Close write handle - lh.close(); - - // Open read handle - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - - // Make sure to read all 10 entries. - for (int i = 0; i < 11; i++) { - lh.readEntries(i, i); - } - lh.close(); - bkc.deleteLedger(ledgerId); - } - - /** - * Verify Advanced asynchronous writing with entryIds in pseudo random order with bookie failures between writes. - */ - @Test - public void testLedgerCreateAdvWithRandomAsyncWritesWithBookieFailuresBetweenWrites() throws Exception { - // Create ledgers - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - lh2 = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - - LOG.info("Ledger ID-1: " + lh.getId()); - LOG.info("Ledger ID-2: " + lh2.getId()); - SyncObj syncObj1 = new SyncObj(); - SyncObj syncObj2 = new SyncObj(); - int batchSize = 5; - int i, j; - - // Fill the result buffers first - for (i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - try { - entries1.add(0, entry.array()); - entries2.add(0, entry.array()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - for (i = 0; i < batchSize; i++) { - for (j = i; j < numEntriesToWrite; j = j + batchSize) { - byte[] entry1 = entries1.get(j); - byte[] entry2 = entries2.get(j); - lh.asyncAddEntry(j, entry1, 0, entry1.length, this, syncObj1); - lh2.asyncAddEntry(j, entry2, 0, entry2.length, this, syncObj2); - if (j == numEntriesToWrite / 2) { - // Start One more bookie and shutdown one from last ensemble at half-way - startNewBookie(); - List ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet() - .iterator().next().getValue(); - killBookie(ensemble.get(0)); - } - } - } - - // Wait for all entries to be acknowledged for the first ledger - synchronized (syncObj1) { - while (syncObj1.counter < numEntriesToWrite) { - syncObj1.wait(); - } - assertEquals(BKException.Code.OK, syncObj1.rc); - } - // Wait for all entries to be acknowledged for the second ledger - synchronized (syncObj2) { - while (syncObj2.counter < numEntriesToWrite) { - syncObj2.wait(); - } - assertEquals(BKException.Code.OK, syncObj2.rc); - } - - // Reading ledger till the last entry - readEntries(lh, entries1); - readEntries(lh2, entries2); - lh.close(); - lh2.close(); - } - - /** - * Verify Advanced asynchronous writing with entryIds in pseudo random order. - */ - @Test - public void testLedgerCreateAdvWithRandomAsyncWritesWithBookieFailures() throws Exception { - // Create ledgers - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - lh2 = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - - LOG.info("Ledger ID-1: " + lh.getId()); - LOG.info("Ledger ID-2: " + lh2.getId()); - SyncObj syncObj1 = new SyncObj(); - SyncObj syncObj2 = new SyncObj(); - int batchSize = 5; - int i, j; - - // Fill the result buffers first - for (i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - try { - entries1.add(0, entry.array()); - entries2.add(0, entry.array()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - for (i = 0; i < batchSize; i++) { - for (j = i; j < numEntriesToWrite; j = j + batchSize) { - byte[] entry1 = entries1.get(j); - byte[] entry2 = entries2.get(j); - lh.asyncAddEntry(j, entry1, 0, entry1.length, this, syncObj1); - lh2.asyncAddEntry(j, entry2, 0, entry2.length, this, syncObj2); - } - } - // Start One more bookie and shutdown one from last ensemble before reading - startNewBookie(); - List ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next() - .getValue(); - killBookie(ensemble.get(0)); - - // Wait for all entries to be acknowledged for the first ledger - synchronized (syncObj1) { - while (syncObj1.counter < numEntriesToWrite) { - syncObj1.wait(); - } - assertEquals(BKException.Code.OK, syncObj1.rc); - } - // Wait for all entries to be acknowledged for the second ledger - synchronized (syncObj2) { - while (syncObj2.counter < numEntriesToWrite) { - syncObj2.wait(); - } - assertEquals(BKException.Code.OK, syncObj2.rc); - } - - // Reading ledger till the last entry - readEntries(lh, entries1); - readEntries(lh2, entries2); - lh.close(); - lh2.close(); - } - - /** - * Skips few entries before closing the ledger and assert that the - * lastAddConfirmed is right before our skipEntryId. - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdvWithSkipEntries() throws Exception { - long ledgerId; - SyncObj syncObj1 = new SyncObj(); - - // Create a ledger - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - // Save ledgerId to reopen the ledger - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + ledgerId); - int skipEntryId = rng.nextInt(numEntriesToWrite - 1); - for (int i = numEntriesToWrite - 1; i >= 0; i--) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - try { - entries1.add(0, entry.array()); - } catch (Exception e) { - e.printStackTrace(); - } - if (i == skipEntryId) { - LOG.info("Skipping entry:{}", skipEntryId); - continue; - } - lh.asyncAddEntry(i, entry.array(), 0, entry.capacity(), this, syncObj1); - } - // wait for all entries to be acknowledged for the first ledger - synchronized (syncObj1) { - while (syncObj1.counter < skipEntryId) { - syncObj1.wait(); - } - assertEquals(BKException.Code.OK, syncObj1.rc); - } - // Close the ledger - lh.close(); - // Open the ledger - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - assertEquals(lh.lastAddConfirmed, skipEntryId - 1); - lh.close(); - } - - /** - * Verify the functionality LedgerHandleAdv addEntry with duplicate entryIds. - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdvSyncAddDuplicateEntryIds() throws Exception { - // Create a ledger - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries1.add(entry.array()); - lh.addEntry(i, entry.array()); - entry.position(0); - } - readEntries(lh, entries1); - - int dupEntryId = rng.nextInt(numEntriesToWrite - 1); - - try { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - lh.addEntry(dupEntryId, entry.array()); - fail("Expected exception not thrown"); - } catch (BKException e) { - // This test expects DuplicateEntryIdException - assertEquals(e.getCode(), BKException.Code.DuplicateEntryIdException); - } - lh.close(); - } - - /** - * Verify the functionality LedgerHandleAdv asyncAddEntry with duplicate - * entryIds. - * - * @throws Exception - */ - @Test - public void testLedgerCreateAdvSyncAsyncAddDuplicateEntryIds() throws Exception { - long ledgerId; - SyncObj syncObj1 = new SyncObj(); - SyncObj syncObj2 = new SyncObj(); - - // Create a ledger - lh = bkc.createLedgerAdv(5, 3, 2, digestType, ledgerPassword); - // Save ledgerId to reopen the ledger - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + ledgerId); - for (int i = numEntriesToWrite - 1; i >= 0; i--) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - try { - entries1.add(0, entry.array()); - } catch (Exception e) { - e.printStackTrace(); - } - lh.asyncAddEntry(i, entry.array(), 0, entry.capacity(), this, syncObj1); - if (rng.nextBoolean()) { - // Attempt to write the same entry - lh.asyncAddEntry(i, entry.array(), 0, entry.capacity(), this, syncObj2); - synchronized (syncObj2) { - while (syncObj2.counter < 1) { - syncObj2.wait(); - } - assertEquals(BKException.Code.DuplicateEntryIdException, syncObj2.rc); - } - } - } - // Wait for all entries to be acknowledged for the first ledger - synchronized (syncObj1) { - while (syncObj1.counter < numEntriesToWrite) { - syncObj1.wait(); - } - assertEquals(BKException.Code.OK, syncObj1.rc); - } - // Close the ledger - lh.close(); - } - - @Test - @SuppressWarnings("unchecked") - public void testLedgerCreateAdvByteBufRefCnt() throws Exception { - long ledgerId = rng.nextLong(); - ledgerId &= Long.MAX_VALUE; - if (!baseConf.getLedgerManagerFactoryClass().equals(LongHierarchicalLedgerManagerFactory.class)) { - // since LongHierarchicalLedgerManager supports ledgerIds of - // decimal length upto 19 digits but other - // LedgerManagers only upto 10 decimals - ledgerId %= 9999999999L; - } - - final LedgerHandle lh = bkc.createLedgerAdv(ledgerId, 5, 3, 2, digestType, ledgerPassword, null); - - final List allocs = Lists.newArrayList( - new PooledByteBufAllocator(true), - new PooledByteBufAllocator(false), - new UnpooledByteBufAllocator(true), - new UnpooledByteBufAllocator(false)); - - long entryId = 0; - for (AbstractByteBufAllocator alloc: allocs) { - final ByteBuf data = alloc.buffer(10); - data.writeBytes(("fragment0" + entryId).getBytes()); - assertEquals("ref count on ByteBuf should be 1", 1, data.refCnt()); - - CompletableFuture cf = new CompletableFuture<>(); - lh.asyncAddEntry(entryId, data, (rc, handle, eId, qwcLatency, ctx) -> { - CompletableFuture future = (CompletableFuture) ctx; - future.complete(rc); - }, cf); - - int rc = cf.get(); - assertEquals("rc code is OK", BKException.Code.OK, rc); - - for (int i = 0; i < 10; i++) { - if (data.refCnt() == 0) { - break; - } - TimeUnit.MILLISECONDS.sleep(250); // recycler runs asynchronously - } - assertEquals("writing entry with id " + entryId + ", ref count on ByteBuf should be 0 ", - 0, data.refCnt()); - - org.apache.bookkeeper.client.api.LedgerEntry e = lh.read(entryId, entryId).getEntry(entryId); - assertEquals("entry data is correct", "fragment0" + entryId, new String(e.getEntryBytes())); - entryId++; - } - - bkc.deleteLedger(lh.ledgerId); - } - - @Test - @SuppressWarnings("unchecked") - public void testLedgerCreateByteBufRefCnt() throws Exception { - final LedgerHandle lh = bkc.createLedger(5, 3, 2, digestType, ledgerPassword, null); - - final List allocs = Lists.newArrayList( - new PooledByteBufAllocator(true), - new PooledByteBufAllocator(false), - new UnpooledByteBufAllocator(true), - new UnpooledByteBufAllocator(false)); - - int entryId = 0; - for (AbstractByteBufAllocator alloc: allocs) { - final ByteBuf data = alloc.buffer(10); - data.writeBytes(("fragment0" + entryId).getBytes()); - assertEquals("ref count on ByteBuf should be 1", 1, data.refCnt()); - - CompletableFuture cf = new CompletableFuture<>(); - lh.asyncAddEntry(data, (rc, handle, eId, ctx) -> { - CompletableFuture future = (CompletableFuture) ctx; - future.complete(rc); - }, cf); - - int rc = cf.get(); - assertEquals("rc code is OK", BKException.Code.OK, rc); - - for (int i = 0; i < 10; i++) { - if (data.refCnt() == 0) { - break; - } - TimeUnit.MILLISECONDS.sleep(250); // recycler runs asynchronously - } - assertEquals("writing entry with id " + entryId + ", ref count on ByteBuf should be 0 ", - 0, data.refCnt()); - - org.apache.bookkeeper.client.api.LedgerEntry e = lh.read(entryId, entryId).getEntry(entryId); - assertEquals("entry data is correct", "fragment0" + entryId, new String(e.getEntryBytes())); - entryId++; - } - - bkc.deleteLedger(lh.ledgerId); - } - - @Test - public void testReadLacNotSameWithMetadataLedgerReplication() throws Exception { - lh = bkc.createLedger(3, 3, 2, digestType, ledgerPassword); - for (int i = 0; i < 10; ++i) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - lh.addEntry(entry.array()); - } - - List ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next().getValue(); - assertEquals(1, lh.getLedgerMetadata().getAllEnsembles().size()); - killBookie(ensemble.get(1)); - - try { - lh.ensembleChangeLoop(ensemble, Collections.singletonMap(1, ensemble.get(1))); - } catch (Exception e) { - fail(); - } - - LedgerHandle lh1 = bkc.openLedgerNoRecovery(lh.ledgerId, digestType, ledgerPassword); - assertEquals(2, lh1.getLedgerMetadata().getAllEnsembles().size()); - List firstEnsemble = lh1.getLedgerMetadata().getAllEnsembles().firstEntry().getValue(); - - long entryId = lh1.getLedgerMetadata().getAllEnsembles().lastEntry().getKey() - 1; - try { - lh1.readAsync(entryId, entryId).get(); - fail(); - } catch (Exception e) { - LOG.info("Failed to read entry: {} ", entryId, e); - } - - MetadataBookieDriver driver = MetadataDrivers.getBookieDriver( - URI.create(baseConf.getMetadataServiceUri())); - driver.initialize( - baseConf, - NullStatsLogger.INSTANCE); - // initialize urReplicationManager - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - baseConf.setOpenLedgerRereplicationGracePeriod(String.valueOf(30)); - - - ReplicationWorker replicationWorker = new ReplicationWorker(baseConf); - replicationWorker.start(); - String basePath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseClientConf) + '/' - + BookKeeperConstants.UNDER_REPLICATION_NODE - + BookKeeperConstants.DEFAULT_ZK_LEDGERS_ROOT_PATH; - - try { - underReplicationManager.markLedgerUnderreplicated(lh1.getId(), ensemble.get(1).toString()); - - Awaitility.waitAtMost(30, TimeUnit.SECONDS).untilAsserted(() -> - assertFalse(ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh1.getId(), basePath)) - ); - - assertNotEquals(firstEnsemble, lh1.getLedgerMetadata().getAllEnsembles().firstEntry().getValue()); - } finally { - replicationWorker.shutdown(); - } - } - - @Test - public void testLedgerMetadataTest() throws Exception { - baseClientConf.setLedgerMetadataFormatVersion(LedgerMetadataSerDe.METADATA_FORMAT_VERSION_2); - BookKeeperTestClient bkc = new BookKeeperTestClient(baseClientConf, new TestStatsProvider()); - // Create a ledger - lh = bkc.createLedger(3, 3, 2, digestType, ledgerPassword); - assertEquals(lh.getLedgerMetadata().getMetadataFormatVersion(), LedgerMetadataSerDe.METADATA_FORMAT_VERSION_2); - lh.close(); - } - - private void readEntries(LedgerHandle lh, List entries) throws InterruptedException, BKException { - ls = lh.readEntries(0, numEntriesToWrite - 1); - int index = 0; - while (ls.hasMoreElements()) { - ByteBuffer origbb = ByteBuffer.wrap(entries.get(index++)); - Integer origEntry = origbb.getInt(); - ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry()); - Integer retrEntry = result.getInt(); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - LOG.debug("Original entry: " + origEntry); - LOG.debug("Retrieved entry: " + retrEntry); - } - assertTrue("Checking entry " + index + " for equality", origEntry - .equals(retrEntry)); - } - } - - private void readEntries(ReadHandle reader, List entries) throws Exception { - assertEquals("Not enough entries in ledger " + reader.getId(), - reader.getLastAddConfirmed(), entries.size() - 1); - try (LedgerEntries readEntries = reader.read(0, reader.getLastAddConfirmed())) { - int i = 0; - for (org.apache.bookkeeper.client.api.LedgerEntry e : readEntries) { - int entryId = i++; - ByteBuf origEntry = entries.get(entryId); - ByteBuf readEntry = e.getEntryBuffer(); - assertEquals("Unexpected contents in " + reader.getId() + ":" + entryId, origEntry, readEntry); - } - } - } - - private void readEntriesAndValidateDataArray(LedgerHandle lh, List entries) - throws InterruptedException, BKException { - ls = lh.readEntries(0, entries.size() - 1); - int index = 0; - while (ls.hasMoreElements()) { - byte[] originalData = entries.get(index++); - byte[] receivedData = ls.nextElement().getEntry(); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of originalData: {}", originalData.length); - LOG.debug("Length of receivedData: {}", receivedData.length); - } - assertEquals( - String.format("LedgerID: %d EntryID: %d OriginalDataLength: %d ReceivedDataLength: %d", lh.getId(), - (index - 1), originalData.length, receivedData.length), - originalData.length, receivedData.length); - Assert.assertArrayEquals( - String.format("Checking LedgerID: %d EntryID: %d for equality", lh.getId(), (index - 1)), - originalData, receivedData); - } - } - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - SyncObj x = (SyncObj) ctx; - synchronized (x) { - x.rc = rc; - x.counter++; - x.notify(); - } - } - - static class CorruptReadBookie extends TestBookieImpl { - - static final Logger LOG = LoggerFactory.getLogger(CorruptReadBookie.class); - ByteBuf localBuf; - - public CorruptReadBookie(ServerConfiguration conf) - throws Exception { - super(conf); - } - - @Override - public ByteBuf readEntry(long ledgerId, long entryId) throws IOException, NoLedgerException, BookieException { - localBuf = super.readEntry(ledgerId, entryId); - - int capacity = 0; - while (capacity < localBuf.capacity()) { - localBuf.setByte(capacity, 0); - capacity++; - } - return localBuf; - } - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgersWithDifferentDigestsTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgersWithDifferentDigestsTest.java deleted file mode 100644 index c93d65e40aa..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgersWithDifferentDigestsTest.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.bookie.BookieException.Code.OK; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.Random; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Verify reads from ledgers with different digest types. - * This can happen as result of clients using different settings - * yet reading each other data or configuration change roll out. - */ -@RunWith(Parameterized.class) -public class BookieWriteLedgersWithDifferentDigestsTest extends - BookKeeperClusterTestCase implements AsyncCallback.AddCallbackWithLatency { - - private static final Logger LOG = LoggerFactory - .getLogger(BookieWriteLedgersWithDifferentDigestsTest.class); - - byte[] ledgerPassword = "aaa".getBytes(); - LedgerHandle lh; - Enumeration ls; - - // test related variables - final int numEntriesToWrite = 20; - int maxInt = Integer.MAX_VALUE; - Random rng; - ArrayList entries1; // generated entries - ArrayList entries2; // generated entries - - private final DigestType digestType; - private final DigestType otherDigestType; - - private static class SyncObj { - volatile int counter; - volatile int rc; - - public SyncObj() { - counter = 0; - } - } - - @Parameterized.Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { {DigestType.MAC }, {DigestType.CRC32}, {DigestType.CRC32C} }); - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - rng = new Random(System.currentTimeMillis()); // Initialize the Random - // Number Generator - entries1 = new ArrayList(); // initialize the entries list - entries2 = new ArrayList(); // initialize the entries list - } - - public BookieWriteLedgersWithDifferentDigestsTest(DigestType digestType) { - super(3); - this.digestType = digestType; - this.otherDigestType = digestType == DigestType.CRC32 ? DigestType.MAC : DigestType.CRC32; - String ledgerManagerFactory = "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"; - // set ledger manager - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - @Test - public void testLedgersWithDifferentDigestTypesNoAutodetection() throws Exception { - bkc.conf.setEnableDigestTypeAutodetection(false); - // Create ledgers - lh = bkc.createLedgerAdv(3, 2, 2, digestType, ledgerPassword); - - final long id = lh.ledgerId; - - LOG.info("Ledger ID: {}, digestType: {}", lh.getId(), digestType); - SyncObj syncObj1 = new SyncObj(); - for (int i = numEntriesToWrite - 1; i >= 0; i--) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries1.add(0, entry.array()); - lh.asyncAddEntry(i, entry.array(), 0, entry.capacity(), this, syncObj1); - } - - // Wait for all entries to be acknowledged - waitForEntriesAddition(syncObj1, numEntriesToWrite); - - // Reads here work ok because ledger uses digest type set during create - readEntries(lh, entries1); - lh.close(); - - try { - bkc.openLedgerNoRecovery(id, otherDigestType, ledgerPassword).close(); - fail("digest mismatch error is expected"); - } catch (BKException bke) { - // expected - } - } - - @Test - public void testLedgersWithDifferentDigestTypesWithAutodetection() throws Exception { - bkc.conf.setEnableDigestTypeAutodetection(true); - // Create ledgers - lh = bkc.createLedgerAdv(3, 2, 2, digestType, ledgerPassword); - - final long id = lh.ledgerId; - - LOG.info("Ledger ID-1: " + lh.getId()); - SyncObj syncObj1 = new SyncObj(); - for (int i = numEntriesToWrite - 1; i >= 0; i--) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries1.add(0, entry.array()); - lh.asyncAddEntry(i, entry.array(), 0, entry.capacity(), this, syncObj1); - } - - // Wait for all entries to be acknowledged - waitForEntriesAddition(syncObj1, numEntriesToWrite); - - // Reads here work ok because ledger uses digest type set during create - readEntries(lh, entries1); - lh.close(); - - // open here would fail if provided digest type is used - // it passes because ledger just uses digest type from its metadata/autodetects it - lh = bkc.openLedgerNoRecovery(id, otherDigestType, ledgerPassword); - readEntries(lh, entries1); - lh.close(); - } - - private void waitForEntriesAddition(SyncObj syncObj, int numEntriesToWrite) throws InterruptedException { - synchronized (syncObj) { - while (syncObj.counter < numEntriesToWrite) { - syncObj.wait(); - } - assertEquals(BKException.Code.OK, syncObj.rc); - } - } - - private void readEntries(LedgerHandle lh, ArrayList entries) throws InterruptedException, BKException { - ls = lh.readEntries(0, numEntriesToWrite - 1); - int index = 0; - while (ls.hasMoreElements()) { - ByteBuffer origbb = ByteBuffer.wrap(entries.get(index++)); - Integer origEntry = origbb.getInt(); - ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry()); - Integer retrEntry = result.getInt(); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - LOG.debug("Original entry: " + origEntry); - LOG.debug("Retrieved entry: " + retrEntry); - } - assertTrue("Checking entry " + index + " for equality", origEntry - .equals(retrEntry)); - } - } - - @Override - public void addCompleteWithLatency(int rc, LedgerHandle lh, long entryId, long qwcLatency, Object ctx) { - SyncObj x = (SyncObj) ctx; - captureThrowable(() -> { - assertTrue("Successful write should have non-zero latency", rc != OK || qwcLatency > 0); - }); - synchronized (x) { - x.rc = rc; - x.counter++; - x.notify(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ClientUtil.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ClientUtil.java deleted file mode 100644 index 3f8af53c133..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ClientUtil.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.security.GeneralSecurityException; -import java.util.function.Function; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.versioning.Versioned; - -/** - * Client utilities. - */ -public class ClientUtil { - public static final org.apache.bookkeeper.client.api.DigestType DIGEST_TYPE = - org.apache.bookkeeper.client.api.DigestType.CRC32C; - public static final byte[] PASSWD = "foobar".getBytes(UTF_8); - - public static ByteBuf generatePacket(long ledgerId, long entryId, long lastAddConfirmed, - long length, byte[] data) throws GeneralSecurityException { - return generatePacket(ledgerId, entryId, lastAddConfirmed, length, data, 0, data.length); - } - - public static ByteBuf generatePacket(long ledgerId, long entryId, long lastAddConfirmed, long length, byte[] data, - int offset, int len) throws GeneralSecurityException { - DigestManager dm = DigestManager.instantiate(ledgerId, new byte[2], DigestType.CRC32, - UnpooledByteBufAllocator.DEFAULT, true); - return MockBookieClient.copyDataWithSkipHeader(dm.computeDigestAndPackageForSending(entryId, lastAddConfirmed, - length, Unpooled.wrappedBuffer(data, offset, len), new byte[20], 0)); - } - - /** - * Returns that whether ledger is in open state. - */ - public static boolean isLedgerOpen(LedgerHandle handle) { - return !handle.getLedgerMetadata().isClosed(); - } - - public static Versioned setupLedger(ClientContext clientCtx, long ledgerId, - LedgerMetadataBuilder builder) throws Exception { - return setupLedger(clientCtx.getLedgerManager(), ledgerId, builder); - } - - public static Versioned setupLedger(LedgerManager ledgerManager, long ledgerId, - LedgerMetadataBuilder builder) throws Exception { - LedgerMetadata md = builder.withPassword(PASSWD).withDigestType(DIGEST_TYPE).withId(ledgerId).build(); - return ledgerManager.createLedgerMetadata(ledgerId, md).get(); - } - - public static Versioned transformMetadata(ClientContext clientCtx, long ledgerId, - Function transform) - throws Exception { - return transformMetadata(clientCtx.getLedgerManager(), ledgerId, transform); - } - - public static Versioned transformMetadata(LedgerManager ledgerManager, long ledgerId, - Function transform) - throws Exception { - Versioned current = ledgerManager.readLedgerMetadata(ledgerId).get(); - return ledgerManager.writeLedgerMetadata(ledgerId, transform.apply(current.getValue()), - current.getVersion()).get(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ConcurrentV2RecoveryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ConcurrentV2RecoveryTest.java deleted file mode 100644 index 2a8a57735f8..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ConcurrentV2RecoveryTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests concurrent attempts to open and recovery a ledger with V2 protocol. - */ -public class ConcurrentV2RecoveryTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(ConcurrentV2RecoveryTest.class); - private final DigestType digestType; - - public ConcurrentV2RecoveryTest() { - super(4); - this.digestType = DigestType.CRC32; - } - - @Test - public void testConcurrentOpen() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setNumChannelsPerBookie(16) - .setUseV2WireProtocol(true) - .setZkTimeout(20000) - .setAddEntryTimeout(30) - .setReadEntryTimeout(30) - .setSpeculativeReadTimeout(0) - .setThrottleValue(0) - .setLedgerManagerFactoryClassName(HierarchicalLedgerManagerFactory.class.getName()); - - BookKeeper bkc = new BookKeeper(conf); - - for (int j = 0; j < 10; j++) { - LedgerHandle lh = bkc.createLedger(DigestType.CRC32, "testPasswd".getBytes()); - lh.addEntry("foobar".getBytes()); - - long ledgerId = lh.getId(); - final long finalLedgerId = ledgerId; - ExecutorService executor = Executors.newFixedThreadPool(10); - List> futures = new ArrayList<>(); - CountDownLatch latch = new CountDownLatch(1); - for (int i = 0; i < 5; i++) { - final CompletableFuture future = new CompletableFuture<>(); - executor.submit(() -> { - latch.await(); - - bkc.asyncOpenLedger(finalLedgerId, - DigestType.CRC32, "testPasswd".getBytes(), - (rc, handle, ctx) -> { - if (rc != BKException.Code.OK) { - future.completeExceptionally(BKException.create(rc)); - } else { - future.complete(handle); - } - }, null); - return future; - }); - futures.add(future); - } - - latch.countDown(); - for (Future f : futures) { - try { - f.get(10, TimeUnit.SECONDS); - } catch (ExecutionException ee) { - // also fine, recovery can currently fail because of metadata conflicts. - // We should fix this at some point by making the metadata immutable, - // and restarting the entire operation - Assert.assertEquals(ee.getCause().getClass(), BKException.BKLedgerRecoveryException.class); - } - } - } - bkc.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/DeferredSyncTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/DeferredSyncTest.java deleted file mode 100644 index dabf2b6088c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/DeferredSyncTest.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.client.api.WriteAdvHandle; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.net.BookieId; -import org.junit.Test; - -/** - * Client side tests on deferred sync write flag. - */ -public class DeferredSyncTest extends MockBookKeeperTestCase { - - static final byte[] PASSWORD = "password".getBytes(); - static final ByteBuf DATA = Unpooled.wrappedBuffer("foobar".getBytes()); - static final int NUM_ENTRIES = 100; - - @Test - public void testAddEntryLastAddConfirmedDoesNotAdvance() throws Exception { - try (WriteHandle wh = result(newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(2) - .withPassword(PASSWORD) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .execute())) { - for (int i = 0; i < NUM_ENTRIES - 1; i++) { - result(wh.appendAsync(DATA.retainedDuplicate())); - } - long lastEntryID = result(wh.appendAsync(DATA.retainedDuplicate())); - assertEquals(NUM_ENTRIES - 1, lastEntryID); - assertEquals(NUM_ENTRIES - 1, wh.getLastAddPushed()); - assertEquals(-1, wh.getLastAddConfirmed()); - } - } - - @Test - public void testAddEntryLastAddConfirmedAdvanceWithForce() throws Exception { - try (WriteHandle wh = result(newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(2) - .withPassword(PASSWORD) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .execute())) { - for (int i = 0; i < NUM_ENTRIES - 1; i++) { - result(wh.appendAsync(DATA.retainedDuplicate())); - } - long lastEntryID = result(wh.appendAsync(DATA.retainedDuplicate())); - assertEquals(NUM_ENTRIES - 1, lastEntryID); - assertEquals(NUM_ENTRIES - 1, wh.getLastAddPushed()); - assertEquals(-1, wh.getLastAddConfirmed()); - result(wh.force()); - assertEquals(NUM_ENTRIES - 1, wh.getLastAddConfirmed()); - } - } - - @Test - public void testForceOnWriteAdvHandle() throws Exception { - try (WriteAdvHandle wh = result(newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(2) - .withPassword(PASSWORD) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .makeAdv() - .execute())) { - CompletableFuture w0 = wh.writeAsync(0, DATA.retainedDuplicate()); - CompletableFuture w2 = wh.writeAsync(2, DATA.retainedDuplicate()); - CompletableFuture w3 = wh.writeAsync(3, DATA.retainedDuplicate()); - result(w0); - result(wh.force()); - assertEquals(0, wh.getLastAddConfirmed()); - CompletableFuture w1 = wh.writeAsync(1, DATA.retainedDuplicate()); - result(w3); - assertTrue(w1.isDone()); - assertTrue(w2.isDone()); - CompletableFuture w5 = wh.writeAsync(5, DATA.retainedDuplicate()); - result(wh.force()); - assertEquals(3, wh.getLastAddConfirmed()); - wh.writeAsync(4, DATA.retainedDuplicate()); - result(w5); - result(wh.force()); - assertEquals(5, wh.getLastAddConfirmed()); - } - } - - @Test - public void testForceRequiresFullEnsemble() throws Exception { - try (WriteHandle wh = result(newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(2) - .withAckQuorumSize(2) - .withPassword(PASSWORD) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .execute())) { - for (int i = 0; i < NUM_ENTRIES - 1; i++) { - result(wh.appendAsync(DATA.retainedDuplicate())); - } - long lastEntryID = result(wh.appendAsync(DATA.retainedDuplicate())); - assertEquals(NUM_ENTRIES - 1, lastEntryID); - assertEquals(NUM_ENTRIES - 1, wh.getLastAddPushed()); - assertEquals(-1, wh.getLastAddConfirmed()); - - BookieId bookieAddress = wh.getLedgerMetadata().getEnsembleAt(wh.getLastAddPushed()).get(0); - killBookie(bookieAddress); - - // write should succeed (we still have 2 bookies out of 3) - result(wh.appendAsync(DATA.retainedDuplicate())); - - // force cannot go, it must be acknowledged by all of the bookies in the ensamble - try { - result(wh.force()); - } catch (BKException.BKBookieException failed) { - } - // bookie comes up again, force must succeed - startKilledBookie(bookieAddress); - result(wh.force()); - } - } - - @Test - public void testForceWillAdvanceLacOnlyUpToLastAcknoledgedWrite() throws Exception { - try (WriteHandle wh = result(newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(3) - .withPassword(PASSWORD) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .execute())) { - for (int i = 0; i < NUM_ENTRIES - 1; i++) { - result(wh.appendAsync(DATA.retainedDuplicate())); - } - long lastEntryIdBeforeSuspend = result(wh.appendAsync(DATA.retainedDuplicate())); - assertEquals(NUM_ENTRIES - 1, lastEntryIdBeforeSuspend); - assertEquals(-1, wh.getLastAddConfirmed()); - - // one bookie will stop sending acks for forceLedger - BookieId bookieAddress = wh.getLedgerMetadata().getEnsembleAt(wh.getLastAddPushed()).get(0); - suspendBookieForceLedgerAcks(bookieAddress); - - // start and complete a force, lastAddConfirmed cannot be "lastAddPushedAfterSuspendedWrite" - // because the write has not yet been acknowledged by AckQuorumSize Bookies - CompletableFuture forceResult = wh.force(); - assertEquals(-1, wh.getLastAddConfirmed()); - - // send an entry and receive ack - long lastEntry = wh.append(DATA.retainedDuplicate()); - - // receive the ack for forceLedger - resumeBookieWriteAcks(bookieAddress); - result(forceResult); - - // now LastAddConfirmed will be equals to the last confirmed entry - // before force() started - assertEquals(lastEntryIdBeforeSuspend, wh.getLastAddConfirmed()); - - result(wh.force()); - assertEquals(lastEntry, wh.getLastAddConfirmed()); - } - } - - @Test - public void testForbiddenEnsembleChange() throws Exception { - try (WriteHandle wh = result(newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .withPassword(PASSWORD) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .execute())) { - for (int i = 0; i < NUM_ENTRIES - 1; i++) { - wh.append(DATA.retainedDuplicate()); - } - - assertEquals(1, availableBookies.size()); - // kill the only bookie in the ensamble - killBookie(wh.getLedgerMetadata().getEnsembleAt(wh.getLastAddPushed()).get(0)); - assertEquals(0, availableBookies.size()); - startNewBookie(); - assertEquals(1, availableBookies.size()); - - try { - // we cannot switch to the new bookie with DEFERRED_SYNC - wh.append(DATA.retainedDuplicate()); - fail("since ensemble change is disable we cannot be able to write any more"); - } catch (BKException.BKWriteException ex) { - // expected - } - LedgerHandle lh = (LedgerHandle) wh; - assertFalse(lh.hasDelayedWriteFailedBookies()); - } - } - - @Test(expected = BKException.BKLedgerClosedException.class) - public void testCannotIssueForceOnClosedLedgerHandle() throws Exception { - WriteHandle wh = result(newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .withPassword(PASSWORD) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .execute()); - wh.close(); - result(wh.force()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ExplicitLacTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ExplicitLacTest.java deleted file mode 100644 index 42d1aebf6ac..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ExplicitLacTest.java +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.SortedLedgerStorage; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.TestUtils; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * Test cases for `Explicit Lac` feature. - */ -@RunWith(Parameterized.class) -public class ExplicitLacTest extends BookKeeperClusterTestCase { - - private final DigestType digestType; - - public ExplicitLacTest(Class storageClass) { - super(1); - this.digestType = DigestType.CRC32; - baseConf.setLedgerStorageClass(storageClass.getName()); - /* - * to persist explicitLac, journalFormatVersionToWrite should be atleast - * V6 and fileInfoFormatVersionToWrite should be atleast V1 - */ - baseConf.setJournalFormatVersionToWrite(6); - baseConf.setFileInfoFormatVersionToWrite(1); - } - - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { - { InterleavedLedgerStorage.class }, - { SortedLedgerStorage.class }, - { DbLedgerStorage.class }, - }); - } - - @Test - public void testReadHandleWithNoExplicitLAC() throws Exception { - ClientConfiguration confWithNoExplicitLAC = new ClientConfiguration(); - confWithNoExplicitLAC.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - confWithNoExplicitLAC.setExplictLacInterval(0); - - BookKeeper bkcWithNoExplicitLAC = new BookKeeper(confWithNoExplicitLAC); - - LedgerHandle wlh = bkcWithNoExplicitLAC.createLedger( - 1, 1, 1, - digestType, "testPasswd".getBytes()); - long ledgerId = wlh.getId(); - int numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - LedgerHandle rlh = bkcWithNoExplicitLAC.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes()); - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - Enumeration entries = rlh.readEntries(0, numOfEntries - 2); - int entryId = 0; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - String entryString = new String(entry.getEntry()); - assertTrue("Expected entry String: " + ("foobar" + entryId) + " actual entry String: " + entryString, - entryString.equals("foobar" + entryId)); - entryId++; - } - - for (int i = numOfEntries; i < 2 * numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - TestUtils.waitUntilLacUpdated(rlh, numOfEntries - 2); - - assertTrue( - "Expected LAC of wlh: " + (2 * numOfEntries - 1) + " actual LAC of rlh: " + wlh.getLastAddConfirmed(), - (wlh.getLastAddConfirmed() == (2 * numOfEntries - 1))); - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - // since explicitlacflush policy is not enabled for writeledgerhandle, when we try - // to read explicitlac for rlh, it will be reading up to the piggyback value. - long explicitlac = rlh.readExplicitLastConfirmed(); - assertTrue( - "Expected Explicit LAC of rlh: " + (numOfEntries - 2) + " actual ExplicitLAC of rlh: " + explicitlac, - (explicitlac == (2 * numOfEntries - 2))); - - try { - rlh.readEntries(2 * numOfEntries - 1, 2 * numOfEntries - 1); - fail("rlh readEntries beyond " + (2 * numOfEntries - 2) + " should fail with ReadException"); - } catch (BKException.BKReadException readException) { - } - - rlh.close(); - wlh.close(); - bkcWithNoExplicitLAC.close(); - } - - @Test - public void testExplicitLACIsPersisted() throws Exception { - ClientConfiguration confWithNoExplicitLAC = new ClientConfiguration(); - confWithNoExplicitLAC.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - // enable explicitLacFlush by setting non-zero value for - // explictLacInterval - confWithNoExplicitLAC.setExplictLacInterval(50); - - BookKeeper bkcWithExplicitLAC = new BookKeeper(confWithNoExplicitLAC); - - LedgerHandle wlh = bkcWithExplicitLAC.createLedger(1, 1, 1, digestType, "testPasswd".getBytes()); - long ledgerId = wlh.getId(); - int numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - LedgerHandle rlh = bkcWithExplicitLAC.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes()); - assertEquals("LAC of rlh", (long) numOfEntries - 2, rlh.getLastAddConfirmed()); - - for (int i = numOfEntries; i < 2 * numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - assertEquals("LAC of wlh", (2 * numOfEntries - 1), wlh.getLastAddConfirmed()); - assertEquals("LAC of rlh", (long) numOfEntries - 2, rlh.getLastAddConfirmed()); - assertEquals("Read LAC of rlh", (2 * numOfEntries - 2), rlh.readLastAddConfirmed()); - assertEquals("Read explicit LAC of rlh", (2 * numOfEntries - 2), rlh.readExplicitLastConfirmed()); - - // we need to wait for atleast 2 explicitlacintervals, - // since in writehandle for the first call - // lh.getExplicitLastAddConfirmed() will be < - // lh.getPiggyBackedLastAddConfirmed(), - // so it wont make explicit writelac in the first run - long readExplicitLastConfirmed = TestUtils.waitUntilExplicitLacUpdated(rlh, 2 * numOfEntries - 1); - assertEquals("Read explicit LAC of rlh after wait for explicitlacflush", (2 * numOfEntries - 1), - readExplicitLastConfirmed); - - // bookies have to be restarted - restartBookies(); - - /* - * since explicitLac is persisted we should be able to read explicitLac - * from the bookies. - */ - LedgerHandle rlh2 = bkcWithExplicitLAC.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes()); - assertEquals("Read explicit LAC of rlh2 after bookies restart", (2 * numOfEntries - 1), - rlh2.readExplicitLastConfirmed()); - bkcWithExplicitLAC.close(); - } - - @Test - public void testReadHandleWithExplicitLAC() throws Exception { - ClientConfiguration confWithExplicitLAC = new ClientConfiguration(); - confWithExplicitLAC.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int explicitLacIntervalMillis = 1000; - confWithExplicitLAC.setExplictLacInterval(explicitLacIntervalMillis); - - BookKeeper bkcWithExplicitLAC = new BookKeeper(confWithExplicitLAC); - - LedgerHandle wlh = bkcWithExplicitLAC.createLedger( - 1, 1, 1, - digestType, "testPasswd".getBytes()); - long ledgerId = wlh.getId(); - int numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - LedgerHandle rlh = bkcWithExplicitLAC.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes()); - - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - for (int i = numOfEntries; i < 2 * numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - // we need to wait for atleast 2 explicitlacintervals, - // since in writehandle for the first call - // lh.getExplicitLastAddConfirmed() will be < - // lh.getPiggyBackedLastAddConfirmed(), - // so it wont make explicit writelac in the first run - TestUtils.waitUntilLacUpdated(rlh, 2 * numOfEntries - 2); - - assertTrue( - "Expected LAC of wlh: " + (2 * numOfEntries - 1) + " actual LAC of wlh: " + wlh.getLastAddConfirmed(), - (wlh.getLastAddConfirmed() == (2 * numOfEntries - 1))); - // readhandle's lastaddconfirmed wont be updated until readExplicitLastConfirmed call is made - assertTrue( - "Expected LAC of rlh: " + (2 * numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (2 * numOfEntries - 2))); - - long explicitlac = TestUtils.waitUntilExplicitLacUpdated(rlh, 2 * numOfEntries - 1); - assertTrue("Expected Explicit LAC of rlh: " + (2 * numOfEntries - 1) - + " actual ExplicitLAC of rlh: " + explicitlac, - (explicitlac == (2 * numOfEntries - 1))); - // readExplicitLastConfirmed updates the lac of rlh. - assertTrue( - "Expected LAC of rlh: " + (2 * numOfEntries - 1) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (2 * numOfEntries - 1))); - - Enumeration entries = rlh.readEntries(numOfEntries, 2 * numOfEntries - 1); - int entryId = numOfEntries; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - String entryString = new String(entry.getEntry()); - assertTrue("Expected entry String: " + ("foobar" + entryId) + " actual entry String: " + entryString, - entryString.equals("foobar" + entryId)); - entryId++; - } - - rlh.close(); - wlh.close(); - bkcWithExplicitLAC.close(); - } - - @Test - public void testReadHandleWithExplicitLACAndDeferredSync() throws Exception { - ClientConfiguration confWithExplicitLAC = new ClientConfiguration(); - confWithExplicitLAC.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - int explicitLacIntervalMillis = 1000; - confWithExplicitLAC.setExplictLacInterval(explicitLacIntervalMillis); - - BookKeeper bkcWithExplicitLAC = new BookKeeper(confWithExplicitLAC); - - LedgerHandle wlh = (LedgerHandle) bkcWithExplicitLAC.newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(1) - .withWriteFlags(WriteFlag.DEFERRED_SYNC) - .withDigestType(digestType.toApiDigestType()) - .withPassword("testPasswd".getBytes()) - .execute() - .get(); - long ledgerId = wlh.getId(); - - // start like testReadHandleWithExplicitLAC - int numOfEntries = 5; - for (int i = 0; i < numOfEntries; i++) { - // if you perform force() + addEntry() you will piggy back LAC as usual - wlh.force().get(); - wlh.addEntry(("foobar" + i).getBytes()); - } - - LedgerHandle rlh = bkcWithExplicitLAC.openLedgerNoRecovery(ledgerId, digestType, "testPasswd".getBytes()); - - assertTrue( - "Expected LAC of rlh: " + (numOfEntries - 2) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (numOfEntries - 2))); - - for (int i = numOfEntries; i < 2 * numOfEntries; i++) { - wlh.addEntry(("foobar" + i).getBytes()); - } - - // running a force() will update local LAC on the writer - // ExplicitLAC timer will send the value even without writes - wlh.force().get(); - - // wait for explicit lac to be sent to bookies - TestUtils.waitUntilExplicitLacUpdated(rlh, 2 * numOfEntries - 2); - - // we need to wait for atleast 2 explicitlacintervals, - // since in writehandle for the first call - // lh.getExplicitLastAddConfirmed() will be < - // lh.getPiggyBackedLastAddConfirmed(), - // so it wont make explicit writelac in the first run - TestUtils.waitUntilLacUpdated(rlh, 2 * numOfEntries - 2); - - assertTrue( - "Expected LAC of wlh: " + (2 * numOfEntries - 1) + " actual LAC of wlh: " + wlh.getLastAddConfirmed(), - (wlh.getLastAddConfirmed() == (2 * numOfEntries - 1))); - - long explicitlac = TestUtils.waitUntilExplicitLacUpdated(rlh, 2 * numOfEntries - 1); - assertTrue("Expected Explicit LAC of rlh: " + (2 * numOfEntries - 1) - + " actual ExplicitLAC of rlh: " + explicitlac, - (explicitlac == (2 * numOfEntries - 1))); - // readExplicitLastConfirmed updates the lac of rlh. - assertTrue( - "Expected LAC of rlh: " + (2 * numOfEntries - 1) + " actual LAC of rlh: " + rlh.getLastAddConfirmed(), - (rlh.getLastAddConfirmed() == (2 * numOfEntries - 1))); - - Enumeration entries = rlh.readEntries(numOfEntries, 2 * numOfEntries - 1); - int entryId = numOfEntries; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - String entryString = new String(entry.getEntry()); - assertTrue("Expected entry String: " + ("foobar" + entryId) + " actual entry String: " + entryString, - entryString.equals("foobar" + entryId)); - entryId++; - } - - rlh.close(); - wlh.close(); - bkcWithExplicitLAC.close(); - } - - @Test - public void fallbackV3() throws Exception { - ClientConfiguration v2Conf = new ClientConfiguration(); - v2Conf.setUseV2WireProtocol(true); - v2Conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - v2Conf.setExplictLacInterval(10); - - BookKeeper bookKeeper = new BookKeeper(v2Conf); - LedgerHandle write = (LedgerHandle) bookKeeper.createLedger(1, - 1, - 1, - DigestType.MAC, - "pass".getBytes()); - write.addEntry("test".getBytes()); - TestUtils.waitUntilExplicitLacUpdated(write, 0); - long lac = write.readExplicitLastConfirmed(); - assertEquals(0, lac); - write.close(); - bookKeeper.close(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/GenericEnsemblePlacementPolicyTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/GenericEnsemblePlacementPolicyTest.java deleted file mode 100644 index 094cf064ef1..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/GenericEnsemblePlacementPolicyTest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * Testing a generic ensemble placement policy. - */ -@RunWith(Parameterized.class) -public class GenericEnsemblePlacementPolicyTest extends BookKeeperClusterTestCase { - - private BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - private static final String PASSWORD = "testPasswd"; - private static final String property = "foo"; - private static final byte[] value = "bar".getBytes(StandardCharsets.UTF_8); - private static List> customMetadataOnNewEnsembleStack = new ArrayList<>(); - private static List> customMetadataOnReplaceBookieStack = new ArrayList<>(); - - @Parameters - public static Collection getDiskWeightBasedPlacementEnabled() { - return Arrays.asList(new Object[][] { { false }, { true } }); - } - - public GenericEnsemblePlacementPolicyTest(boolean diskWeightBasedPlacementEnabled) { - super(0); - baseClientConf.setEnsemblePlacementPolicy(CustomEnsemblePlacementPolicy.class); - baseClientConf.setDiskWeightBasedPlacementEnabled(diskWeightBasedPlacementEnabled); - } - - /** - * A custom ensemble placement policy. - */ - public static final class CustomEnsemblePlacementPolicy extends DefaultEnsemblePlacementPolicy { - - @Override - public PlacementResult replaceBookie(int ensembleSize, int writeQuorumSize, - int ackQuorumSize, Map customMetadata, List currentEnsemble, - BookieId bookieToReplace, Set excludeBookies) - throws BKException.BKNotEnoughBookiesException { - new Exception("replaceBookie " + ensembleSize + "," + customMetadata).printStackTrace(); - assertNotNull(customMetadata); - customMetadataOnReplaceBookieStack.add(customMetadata); - return super.replaceBookie(ensembleSize, writeQuorumSize, ackQuorumSize, customMetadata, - currentEnsemble, bookieToReplace, excludeBookies); - } - - @Override - public PlacementResult> newEnsemble(int ensembleSize, int quorumSize, - int ackQuorumSize, Map customMetadata, Set excludeBookies) - throws BKException.BKNotEnoughBookiesException { - assertNotNull(customMetadata); - customMetadataOnNewEnsembleStack.add(customMetadata); - return super.newEnsemble(ensembleSize, quorumSize, ackQuorumSize, customMetadata, excludeBookies); - } - } - - @Before - public void reset() { - customMetadataOnNewEnsembleStack.clear(); - customMetadataOnReplaceBookieStack.clear(); - } - - @Test - public void testNewEnsemble() throws Exception { - numBookies = 1; - startBKCluster(zkUtil.getMetadataServiceUri()); - try { - Map customMetadata = new HashMap<>(); - customMetadata.put(property, value); - try (BookKeeper bk = new BookKeeper(baseClientConf, zkc)) { - bk.createLedger(1, 1, 1, digestType, PASSWORD.getBytes(), customMetadata); - } - assertEquals(1, customMetadataOnNewEnsembleStack.size()); - assertArrayEquals(value, customMetadataOnNewEnsembleStack.get(0).get(property)); - } finally { - stopBKCluster(); - } - } - - @Test - public void testNewEnsembleWithNotEnoughtBookies() throws Exception { - numBookies = 0; - try { - startBKCluster(zkUtil.getMetadataServiceUri()); - Map customMetadata = new HashMap<>(); - customMetadata.put(property, value); - try (BookKeeper bk = new BookKeeper(baseClientConf, zkc)) { - bk.createLedger(1, 1, 1, digestType, PASSWORD.getBytes(), customMetadata); - fail("creation should fail"); - } catch (BKException.BKNotEnoughBookiesException bneb) { - } - assertEquals(2, customMetadataOnNewEnsembleStack.size()); - assertArrayEquals(value, customMetadataOnNewEnsembleStack.get(0).get(property)); - assertArrayEquals(value, customMetadataOnNewEnsembleStack.get(1).get(property)); - } finally { - stopBKCluster(); - } - } - - @Test - public void testReplaceBookie() throws Exception { - numBookies = 3; - startBKCluster(zkUtil.getMetadataServiceUri()); - try { - Map customMetadata = new HashMap<>(); - customMetadata.put(property, value); - try (BookKeeper bk = new BookKeeper(baseClientConf, zkc)) { - try (LedgerHandle lh = bk.createLedger(2, 2, 2, digestType, PASSWORD.getBytes(), customMetadata)) { - lh.addEntry(value); - long lId = lh.getId(); - List ensembleAtFirstEntry = lh.getLedgerMetadata().getEnsembleAt(lId); - assertEquals(2, ensembleAtFirstEntry.size()); - killBookie(ensembleAtFirstEntry.get(0)); - lh.addEntry(value); - } - } - assertEquals(2, customMetadataOnNewEnsembleStack.size()); - assertArrayEquals(value, customMetadataOnNewEnsembleStack.get(0).get(property)); - // replaceBookie by default calls newEnsemble, so newEnsemble gets called twice - assertArrayEquals(value, customMetadataOnNewEnsembleStack.get(0).get(property)); - - assertEquals(1, customMetadataOnReplaceBookieStack.size()); - assertArrayEquals(value, customMetadataOnReplaceBookieStack.get(0).get(property)); - - } finally { - stopBKCluster(); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/HandleFailuresTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/HandleFailuresTest.java deleted file mode 100644 index 8e8f5649dad..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/HandleFailuresTest.java +++ /dev/null @@ -1,501 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.util.TestUtils.assertEventuallyTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Lists; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Ledger recovery tests using mocks rather than a real cluster. - */ -public class HandleFailuresTest { - private static final Logger log = LoggerFactory.getLogger(LedgerRecovery2Test.class); - - private static final BookieId b1 = new BookieSocketAddress("b1", 3181).toBookieId(); - private static final BookieId b2 = new BookieSocketAddress("b2", 3181).toBookieId(); - private static final BookieId b3 = new BookieSocketAddress("b3", 3181).toBookieId(); - private static final BookieId b4 = new BookieSocketAddress("b4", 3181).toBookieId(); - private static final BookieId b5 = new BookieSocketAddress("b5", 3181).toBookieId(); - - @Test(timeout = 30000) - public void testChangeTriggeredOneTimeForOneFailure() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create().newEnsembleEntry( - 0L, Lists.newArrayList(b1, b2, b3))); - - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b1); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.appendAsync("entry1".getBytes()); - lh.appendAsync("entry2".getBytes()); - lh.appendAsync("entry3".getBytes()); - lh.appendAsync("entry4".getBytes()); - lh.appendAsync("entry5".getBytes()).get(); - - verify(clientCtx.getLedgerManager(), times(1)).writeLedgerMetadata(anyLong(), any(), any()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b4, b2, b3)); - } - - @Test(timeout = 30000) - public void testSecondFailureOccursWhileFirstBeingHandled() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - clientCtx.getMockRegistrationClient().addBookies(b4, b5).get(); - CompletableFuture b2blocker = new CompletableFuture<>(); - clientCtx.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> { - if (bookie.equals(b1)) { - return FutureUtils.exception(new BKException.BKWriteException()); - } else if (bookie.equals(b2)) { - return b2blocker; - } else { - return FutureUtils.value(null); - } - }); - CompletableFuture metadataNotifier = new CompletableFuture<>(); - CompletableFuture metadataBlocker = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook( - (ledgerId, metadata) -> { - metadataNotifier.complete(null); - return metadataBlocker; - }); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.appendAsync("entry1".getBytes()); - lh.appendAsync("entry2".getBytes()); - lh.appendAsync("entry3".getBytes()); - lh.appendAsync("entry4".getBytes()); - CompletableFuture future = lh.appendAsync("entry5".getBytes()); - - metadataNotifier.get(); // wait for first metadata write to occur - b2blocker.completeExceptionally(new BKException.BKWriteException()); // make b2 requests fail - metadataBlocker.complete(null); - - future.get(); - verify(clientCtx.getLedgerManager(), times(2)).writeLedgerMetadata(anyLong(), any(), any()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b3)); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b4)); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b5)); - } - - @Test(timeout = 30000) - public void testHandlingFailuresOneBookieFailsImmediately() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b1); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.append("entry1".getBytes()); - lh.close(); - - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b4, b2, b3)); - } - - @Test(timeout = 30000) - public void testHandlingFailuresOneBookieFailsAfterOneEntry() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.append("entry1".getBytes()); - clientCtx.getMockBookieClient().errorBookies(b1); - lh.append("entry2".getBytes()); - lh.close(); - - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 2); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(1L), Lists.newArrayList(b4, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), 1L); - } - - @Test(timeout = 30000) - public void testHandlingFailuresMultipleBookieFailImmediatelyNotEnoughToReplace() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - clientCtx.getMockBookieClient().errorBookies(b1, b2); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - try { - lh.append("entry1".getBytes()); - Assert.fail("Shouldn't have been able to add"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // correct behaviour - assertEventuallyTrue("Failure to add should trigger ledger closure", - () -> lh.getLedgerMetadata().isClosed()); - Assert.assertEquals("Ledger should be empty", - lh.getLedgerMetadata().getLastEntryId(), LedgerHandle.INVALID_ENTRY_ID); - Assert.assertEquals("Should be only one ensemble", lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals("Ensemble shouldn't have changed", lh.getLedgerMetadata().getAllEnsembles().get(0L), - Lists.newArrayList(b1, b2, b3)); - } - } - - @Test(timeout = 30000) - public void testHandlingFailuresMultipleBookieFailAfterOneEntryNotEnoughToReplace() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.append("entry1".getBytes()); - - clientCtx.getMockBookieClient().errorBookies(b1, b2); - - try { - lh.append("entry2".getBytes()); - Assert.fail("Shouldn't have been able to add"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // correct behaviour - assertEventuallyTrue("Failure to add should trigger ledger closure", - () -> lh.getLedgerMetadata().isClosed()); - Assert.assertEquals("Ledger should be empty", lh.getLedgerMetadata().getLastEntryId(), 0L); - Assert.assertEquals("Should be only one ensemble", lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals("Ensemble shouldn't have changed", lh.getLedgerMetadata().getAllEnsembles().get(0L), - Lists.newArrayList(b1, b2, b3)); - } - } - - @Test(timeout = 30000) - public void testClientClosesWhileFailureHandlerInProgress() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b2); - - CompletableFuture changeInProgress = new CompletableFuture<>(); - CompletableFuture blockEnsembleChange = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - // block the write trying to replace b2 with b4 - if (metadata.getAllEnsembles().get(0L).get(1).equals(b4)) { - changeInProgress.complete(null); - return blockEnsembleChange; - } else { - return FutureUtils.value(null); - } - }); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - CompletableFuture future = lh.appendAsync("entry1".getBytes()); - changeInProgress.get(); - - lh.close(); - - blockEnsembleChange.complete(null); // allow ensemble change to continue - try { - future.get(); - Assert.fail("Add shouldn't have succeeded"); - } catch (ExecutionException ee) { - Assert.assertEquals(ee.getCause().getClass(), BKException.BKLedgerClosedException.class); - } - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), LedgerHandle.INVALID_ENTRY_ID); - } - - @Test(timeout = 30000) - public void testMetadataSetToClosedDuringFailureHandler() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b2); - - CompletableFuture changeInProgress = new CompletableFuture<>(); - CompletableFuture blockEnsembleChange = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - if (metadata.getAllEnsembles().get(0L).get(1).equals(b4)) { - // block the write trying to replace b2 with b4 - changeInProgress.complete(null); - return blockEnsembleChange; - } else { - return FutureUtils.value(null); - } - }); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - CompletableFuture future = lh.appendAsync("entry1".getBytes()); - changeInProgress.get(); - - ClientUtil.transformMetadata(clientCtx, 10L, - (metadata) -> LedgerMetadataBuilder.from(metadata) - .withClosedState().withLastEntryId(1234L).withLength(10L).build()); - - blockEnsembleChange.complete(null); // allow ensemble change to continue - try { - future.get(); - Assert.fail("Add shouldn't have succeeded"); - } catch (ExecutionException ee) { - Assert.assertEquals(ee.getCause().getClass(), BKException.BKLedgerClosedException.class); - } - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), 1234L); - } - - @Test(timeout = 30000) - public void testMetadataSetToInRecoveryDuringFailureHandler() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b2); - - CompletableFuture changeInProgress = new CompletableFuture<>(); - CompletableFuture blockEnsembleChange = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - if (metadata.getAllEnsembles().get(0L).get(1).equals(b4)) { - // block the write trying to replace b2 with b4 - changeInProgress.complete(null); - return blockEnsembleChange; - } else { - return FutureUtils.value(null); - } - }); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - CompletableFuture future = lh.appendAsync("entry1".getBytes()); - changeInProgress.get(); - - ClientUtil.transformMetadata(clientCtx, 10L, - (metadata) -> LedgerMetadataBuilder.from(metadata).withInRecoveryState().build()); - - blockEnsembleChange.complete(null); // allow ensemble change to continue - try { - future.get(); - Assert.fail("Add shouldn't have succeeded"); - } catch (ExecutionException ee) { - Assert.assertEquals(ee.getCause().getClass(), BKException.BKLedgerFencedException.class); - } - Assert.assertFalse(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - } - - @Test(timeout = 30000) - public void testOldEnsembleChangedDuringFailureHandler() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.append("entry1".getBytes()); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b3); - lh.append("entry2".getBytes()); - - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 2); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(1L), Lists.newArrayList(b1, b2, b4)); - - - CompletableFuture changeInProgress = new CompletableFuture<>(); - CompletableFuture blockEnsembleChange = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - // block the write trying to replace b1 with b5 - if (metadata.getAllEnsembles().size() > 2 - && metadata.getAllEnsembles().get(2L).get(0).equals(b5)) { - changeInProgress.complete(null); - return blockEnsembleChange; - } else { - return FutureUtils.value(null); - } - }); - - clientCtx.getMockRegistrationClient().addBookies(b5).get(); - clientCtx.getMockBookieClient().errorBookies(b1); - - CompletableFuture future = lh.appendAsync("entry3".getBytes()); - changeInProgress.get(); - - ClientUtil.transformMetadata(clientCtx, 10L, - (metadata) -> LedgerMetadataBuilder.from(metadata).replaceEnsembleEntry( - 0L, Lists.newArrayList(b4, b2, b5)).build()); - - blockEnsembleChange.complete(null); // allow ensemble change to continue - future.get(); - - Assert.assertFalse(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 3); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b4, b2, b5)); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(1L), Lists.newArrayList(b1, b2, b4)); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(2L), Lists.newArrayList(b5, b2, b4)); - } - - @Test(timeout = 30000) - public void testNoAddsAreCompletedWhileFailureHandlingInProgress() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b3); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.append("entry1".getBytes()); - - CompletableFuture changeInProgress = new CompletableFuture<>(); - CompletableFuture blockEnsembleChange = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - // block the write trying to replace b3 with b4 - if (metadata.getAllEnsembles().get(1L).get(2).equals(b4)) { - changeInProgress.complete(null); - return blockEnsembleChange; - } else { - return FutureUtils.value(null); - } - }); - - CompletableFuture future = lh.appendAsync("entry2".getBytes()); - changeInProgress.get(); - try { - future.get(1, TimeUnit.SECONDS); - Assert.fail("Shouldn't complete"); - } catch (TimeoutException te) { - } - blockEnsembleChange.complete(null); - future.get(); - - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 2); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(1L), Lists.newArrayList(b1, b2, b4)); - } - - @Test(timeout = 30000) - public void testHandleFailureBookieNotInWriteSet() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(1) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - - CompletableFuture b1Delay = new CompletableFuture<>(); - // Delay the first write to b1, then error it - clientCtx.getMockBookieClient().setPreWriteHook((bookie, ledgerId, entryId) -> { - if (bookie.equals(b1)) { - return b1Delay; - } else { - return FutureUtils.value(null); - } - }); - - CompletableFuture changeInProgress = new CompletableFuture<>(); - CompletableFuture blockEnsembleChange = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - changeInProgress.complete(null); - return blockEnsembleChange; - }); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - log.info("b2 should be enough to complete first add"); - lh.append("entry1".getBytes()); - - log.info("when b1 completes with failure, handleFailures should kick off"); - b1Delay.completeExceptionally(new BKException.BKWriteException()); - - log.info("write second entry, should have enough bookies, but blocks completion on failure handling"); - AtomicReference> e2 = new AtomicReference<>(); - - // Execute appendAsync at the same thread of preWriteHook exception thread. So that the - // `delayedWriteFailedBookies` could update before appendAsync invoke. - ((MockBookieClient) clientCtx.getBookieClient()).getExecutor() - .chooseThread(lh.ledgerId) - .execute(() -> e2.set(lh.appendAsync("entry2".getBytes()))); - changeInProgress.get(); - assertEventuallyTrue("e2 should eventually complete", () -> lh.pendingAddOps.peek().completed); - Assert.assertFalse("e2 shouldn't be completed to client", e2.get().isDone()); - blockEnsembleChange.complete(null); // allow ensemble change to continue - - log.info("e2 should complete"); - e2.get().get(10, TimeUnit.SECONDS); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerClose2Test.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerClose2Test.java deleted file mode 100644 index 40f69304828..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerClose2Test.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import com.google.common.collect.Lists; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Ledger recovery tests using mocks rather than a real cluster. - */ -public class LedgerClose2Test { - private static final Logger log = LoggerFactory.getLogger(LedgerRecovery2Test.class); - - private static final BookieId b1 = new BookieSocketAddress("b1", 3181).toBookieId(); - private static final BookieId b2 = new BookieSocketAddress("b2", 3181).toBookieId(); - private static final BookieId b3 = new BookieSocketAddress("b3", 3181).toBookieId(); - private static final BookieId b4 = new BookieSocketAddress("b4", 3181).toBookieId(); - private static final BookieId b5 = new BookieSocketAddress("b5", 3181).toBookieId(); - - @Test - public void testTryAddAfterCloseHasBeenCalled() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - - for (int i = 0; i < 1000; i++) { - Versioned md = ClientUtil.setupLedger(clientCtx, i, - LedgerMetadataBuilder.create().newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - LedgerHandle lh = new LedgerHandle(clientCtx, i, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - CompletableFuture closeFuture = lh.closeAsync(); - try { - long eid = lh.append("entry".getBytes()); - - // if it succeeds, it should be in final ledge - closeFuture.get(); - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), eid); - } catch (BKException.BKLedgerClosedException bke) { - closeFuture.get(); - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), LedgerHandle.INVALID_ENTRY_ID); - } - } - } - - @Test - public void testMetadataChangedDuringClose() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - lh.append("entry1".getBytes()); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - clientCtx.getMockBookieClient().errorBookies(b3); - lh.append("entry2".getBytes()); - - CompletableFuture closeInProgress = new CompletableFuture<>(); - CompletableFuture blockClose = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - // block the write trying to replace b3 with b4 - if (metadata.isClosed()) { - closeInProgress.complete(null); - return blockClose; - } else { - return FutureUtils.value(null); - } - }); - CompletableFuture closeFuture = lh.closeAsync(); - closeInProgress.get(); - - ClientUtil.transformMetadata(clientCtx, 10L, - (metadata) -> LedgerMetadataBuilder.from(metadata).replaceEnsembleEntry( - 0L, Lists.newArrayList(b4, b2, b5)).build()); - - blockClose.complete(null); - closeFuture.get(); - - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 2); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b4, b2, b5)); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(1L), Lists.newArrayList(b1, b2, b4)); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), 1L); - } - - @Test - public void testMetadataCloseWithCorrectLengthDuringClose() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - long lac = lh.append("entry1".getBytes()); - long length = lh.getLength(); - - CompletableFuture closeInProgress = new CompletableFuture<>(); - CompletableFuture blockClose = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - // block the write trying to do the first close - if (!closeInProgress.isDone() && metadata.isClosed()) { - closeInProgress.complete(null); - return blockClose; - } else { - return FutureUtils.value(null); - } - }); - CompletableFuture closeFuture = lh.closeAsync(); - closeInProgress.get(); - - ClientUtil.transformMetadata(clientCtx, 10L, - (metadata) -> LedgerMetadataBuilder.from(metadata) - .withClosedState().withLastEntryId(lac).withLength(length).build()); - - blockClose.complete(null); - closeFuture.get(); - - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), lac); - Assert.assertEquals(lh.getLedgerMetadata().getLength(), length); - } - - @Test - public void testMetadataCloseWithDifferentLengthDuringClose() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - long lac = lh.append("entry1".getBytes()); - long length = lh.getLength(); - - CompletableFuture closeInProgress = new CompletableFuture<>(); - CompletableFuture blockClose = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - // block the write trying to do the first close - if (!closeInProgress.isDone() && metadata.isClosed()) { - closeInProgress.complete(null); - return blockClose; - } else { - return FutureUtils.value(null); - } - }); - CompletableFuture closeFuture = lh.closeAsync(); - closeInProgress.get(); - - /* close with different length. can happen in cases where there's a write outstanding */ - ClientUtil.transformMetadata(clientCtx, 10L, - (metadata) -> LedgerMetadataBuilder.from(metadata) - .withClosedState().withLastEntryId(lac + 1).withLength(length + 100).build()); - - blockClose.complete(null); - try { - closeFuture.get(); - Assert.fail("Close should fail. Ledger has been closed in a state we don't know how to untangle"); - } catch (ExecutionException ee) { - Assert.assertEquals(ee.getCause().getClass(), BKException.BKMetadataVersionException.class); - } - } - - @Test - public void testMetadataCloseMarkedInRecoveryWhileClosing() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - long lac = lh.append("entry1".getBytes()); - long length = lh.getLength(); - - CompletableFuture closeInProgress = new CompletableFuture<>(); - CompletableFuture blockClose = new CompletableFuture<>(); - clientCtx.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - // block the write trying to do the first close - if (metadata.isClosed()) { - closeInProgress.complete(null); - return blockClose; - } else { - return FutureUtils.value(null); - } - }); - CompletableFuture closeFuture = lh.closeAsync(); - closeInProgress.get(); - - ClientUtil.transformMetadata(clientCtx, 10L, - (metadata) -> LedgerMetadataBuilder.from(metadata).withInRecoveryState().build()); - - blockClose.complete(null); - - closeFuture.get(); // should override in recovery, since this handle knows what it has written - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), lac); - Assert.assertEquals(lh.getLedgerMetadata().getLength(), length); - } - - @Test - public void testCloseWhileAddInProgress() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - Versioned md = ClientUtil.setupLedger(clientCtx, 10L, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - // block all entry writes from completing - CompletableFuture writesHittingBookies = new CompletableFuture<>(); - clientCtx.getMockBookieClient().setPreWriteHook((bookie, ledgerId, entryId) -> { - writesHittingBookies.complete(null); - return new CompletableFuture(); - }); - LedgerHandle lh = new LedgerHandle(clientCtx, 10L, md, BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - CompletableFuture future = lh.appendAsync("entry1".getBytes()); - writesHittingBookies.get(); - - lh.close(); - try { - future.get(); - Assert.fail("That write shouldn't have succeeded"); - } catch (ExecutionException ee) { - Assert.assertEquals(ee.getCause().getClass(), BKException.BKLedgerClosedException.class); - } - Assert.assertTrue(lh.getLedgerMetadata().isClosed()); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), LedgerHandle.INVALID_ENTRY_ID); - Assert.assertEquals(lh.getLedgerMetadata().getLength(), 0); - } - - @Test - public void testDoubleCloseOnHandle() throws Exception { - long ledgerId = 123L; - MockClientContext clientCtx = MockClientContext.create(); - - Versioned md = ClientUtil.setupLedger(clientCtx, ledgerId, - LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(b1, b2, b3))); - - CompletableFuture metadataPromise = new CompletableFuture<>(); - CompletableFuture clientPromise = new CompletableFuture<>(); - - LedgerHandle writer = new LedgerHandle(clientCtx, ledgerId, md, - BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - long eid1 = writer.append("entry1".getBytes()); - - log.info("block writes from completing on bookies and metadata"); - clientCtx.getMockBookieClient().setPostWriteHook((bookie, lid, eid) -> clientPromise); - clientCtx.getMockLedgerManager().setPreWriteHook((lid, metadata) -> metadataPromise); - - log.info("try to add another entry, it will block"); - writer.appendAsync("entry2".getBytes()); - - log.info("attempt one close, should block forever"); - CompletableFuture firstClose = writer.closeAsync(); - - log.info("attempt second close, should not finish before first one"); - CompletableFuture secondClose = writer.closeAsync(); - - Thread.sleep(500); // give it a chance to complete, the request jumps around threads - Assert.assertFalse(firstClose.isDone()); - Assert.assertFalse(secondClose.isDone()); - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCloseTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCloseTest.java deleted file mode 100644 index 496e61f8b44..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCloseTest.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestCallbacks.AddCallbackFuture; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class tests the ledger close logic. - */ -@SuppressWarnings("deprecation") -public class LedgerCloseTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(LedgerCloseTest.class); - - static final int READ_TIMEOUT = 1; - - final DigestType digestType; - - public LedgerCloseTest() { - super(6); - this.digestType = DigestType.CRC32; - // set timeout to a large value which disable it. - baseClientConf.setReadTimeout(99999); - baseConf.setGcWaitTime(999999); - } - - @Test - public void testLedgerCloseWithConsistentLength() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setReadTimeout(1); - - BookKeeper bkc = new BookKeeper(conf); - LedgerHandle lh = bkc.createLedger(6, 3, DigestType.CRC32, new byte[] {}); - final CountDownLatch latch = new CountDownLatch(1); - stopBKCluster(); - final AtomicInteger i = new AtomicInteger(0xdeadbeef); - AsyncCallback.AddCallback cb = new AsyncCallback.AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - i.set(rc); - latch.countDown(); - } - }; - lh.asyncAddEntry("Test Entry".getBytes(), cb, null); - latch.await(); - assertEquals(i.get(), BKException.Code.NotEnoughBookiesException); - assertEquals(0, lh.getLength()); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, lh.getLastAddConfirmed()); - startBKCluster(zkUtil.getMetadataServiceUri()); - LedgerHandle newLh = bkc.openLedger(lh.getId(), DigestType.CRC32, new byte[] {}); - assertEquals(0, newLh.getLength()); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, newLh.getLastAddConfirmed()); - } - - @Test - public void testLedgerCloseDuringUnrecoverableErrors() throws Exception { - int numEntries = 3; - LedgerHandle lh = bkc.createLedger(3, 3, 3, digestType, "".getBytes()); - verifyMetadataConsistency(numEntries, lh); - } - - @Test - public void testLedgerCheckerShouldnotSelectInvalidLastFragments() throws Exception { - int numEntries = 10; - LedgerHandle lh = bkc.createLedger(3, 3, 3, digestType, "".getBytes()); - // Add some entries before bookie failures - for (int i = 0; i < numEntries; i++) { - lh.addEntry("data".getBytes()); - } - numEntries = 4; // add n*ensemleSize+1 entries async after bookies - // failed. - verifyMetadataConsistency(numEntries, lh); - - LedgerChecker checker = new LedgerChecker(bkc); - CheckerCallback cb = new CheckerCallback(); - checker.checkLedger(lh, cb); - Set result = cb.waitAndGetResult(); - assertEquals("No fragments should be selected", 0, result.size()); - } - - class CheckerCallback implements GenericCallback> { - private Set result = null; - private CountDownLatch latch = new CountDownLatch(1); - - public void operationComplete(int rc, Set result) { - this.result = result; - latch.countDown(); - } - - Set waitAndGetResult() throws InterruptedException { - latch.await(); - return result; - } - } - - private void verifyMetadataConsistency(int numEntries, LedgerHandle lh) - throws Exception { - final CountDownLatch addDoneLatch = new CountDownLatch(1); - final CountDownLatch deadIOLatch = new CountDownLatch(1); - final CountDownLatch recoverDoneLatch = new CountDownLatch(1); - final CountDownLatch failedLatch = new CountDownLatch(1); - // kill first bookie to replace with a unauthorize bookie - BookieId bookie = lh.getCurrentEnsemble().get(0); - ServerConfiguration conf = killBookie(bookie); - // replace a unauthorize bookie - startUnauthorizedBookie(conf, addDoneLatch); - // kill second bookie to replace with a dead bookie - bookie = lh.getCurrentEnsemble().get(1); - conf = killBookie(bookie); - // replace a slow dead bookie - startDeadBookie(conf, deadIOLatch); - - // tried to add entries - for (int i = 0; i < numEntries; i++) { - lh.asyncAddEntry("data".getBytes(), new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - if (BKException.Code.OK != rc) { - failedLatch.countDown(); - deadIOLatch.countDown(); - } - if (0 == entryId) { - try { - recoverDoneLatch.await(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - } - } - } - }, null); - } - // add finished - addDoneLatch.countDown(); - // wait until entries failed due to UnauthorizedAccessException - failedLatch.await(); - // simulate the ownership of this ledger is transfer to another host - LOG.info("Recover ledger {}.", lh.getId()); - ClientConfiguration newConf = new ClientConfiguration(); - newConf.addConfiguration(baseClientConf); - BookKeeper newBkc = new BookKeeperTestClient(newConf.setReadTimeout(1)); - LedgerHandle recoveredLh = newBkc.openLedger(lh.getId(), digestType, "".getBytes()); - LOG.info("Recover ledger {} done.", lh.getId()); - recoverDoneLatch.countDown(); - // wait a bit until add operations failed from second bookie due to IOException - TimeUnit.SECONDS.sleep(5); - // open the ledger again to make sure we ge the right last confirmed. - LedgerHandle newLh = newBkc.openLedger(lh.getId(), digestType, "".getBytes()); - assertEquals("Metadata should be consistent across different opened ledgers", - recoveredLh.getLastAddConfirmed(), newLh.getLastAddConfirmed()); - } - - private void startUnauthorizedBookie(ServerConfiguration conf, final CountDownLatch latch) - throws Exception { - Bookie sBookie = new TestBookieImpl(conf) { - @Override - public void addEntry(ByteBuf entry, boolean ackBeforeSync, WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException { - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - throw BookieException.create(BookieException.Code.UnauthorizedAccessException); - } - - @Override - public void recoveryAddEntry(ByteBuf entry, WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException { - throw new IOException("Dead bookie for recovery adds."); - } - }; - startAndAddBookie(conf, sBookie); - } - - // simulate slow adds, then become normal when recover, - // so no ensemble change when recovering ledger on this bookie. - private void startDeadBookie(ServerConfiguration conf, final CountDownLatch latch) throws Exception { - Bookie dBookie = new TestBookieImpl(conf) { - @Override - public void addEntry(ByteBuf entry, boolean ackBeforeSync, WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException { - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - // simulate slow adds. - throw new IOException("Dead bookie"); - } - }; - startAndAddBookie(conf, dBookie); - } - - @Test - public void testAllWritesAreCompletedOnClosedLedger() throws Exception { - for (int i = 0; i < 100; i++) { - LOG.info("Iteration {}", i); - - List futures = new ArrayList(); - LedgerHandle w = bkc.createLedger(DigestType.CRC32, new byte[0]); - AddCallbackFuture f = new AddCallbackFuture(0L); - w.asyncAddEntry("foobar".getBytes(UTF_8), f, null); - f.get(); - - LedgerHandle r = bkc.openLedger(w.getId(), DigestType.CRC32, new byte[0]); - for (int j = 0; j < 100; j++) { - AddCallbackFuture f1 = new AddCallbackFuture(1L + j); - w.asyncAddEntry("foobar".getBytes(), f1, null); - futures.add(f1); - } - - for (AddCallbackFuture f2: futures) { - try { - f2.get(10, TimeUnit.SECONDS); - } catch (ExecutionException ee) { - // we don't care about errors - } catch (TimeoutException te) { - LOG.error("Error on waiting completing entry {} : ", f2.getExpectedEntryId(), te); - fail("Should succeed on waiting completing entry " + f2.getExpectedEntryId()); - } - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCmdTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCmdTest.java deleted file mode 100644 index 6900dfbc13d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCmdTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static junit.framework.TestCase.assertEquals; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.BookieAccessor; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieShell; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.EntryFormatter; -import org.apache.bookkeeper.util.LedgerIdFormatter; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A test for bookieshell ledger command. - */ -public class LedgerCmdTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(LedgerCmdTest.class); - private DigestType digestType = DigestType.CRC32; - private static final String PASSWORD = "testPasswd"; - - public LedgerCmdTest() { - super(1); - baseConf.setLedgerStorageClass(DbLedgerStorage.class.getName()); - baseConf.setGcWaitTime(60000); - baseConf.setFlushInterval(1); - } - - - /** - * list of entry logger files that contains given ledgerId. - */ - @Test - public void testLedgerDbStorageCmd() throws Exception { - - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh1 = createLedgerWithEntries(bk, 10); - - for (int i = 0; i < bookieCount(); i++) { - BookieAccessor.forceFlush((BookieImpl) serverByIndex(i).getBookie()); - } - - String[] argv = { "ledger", Long.toString(lh1.getId()) }; - final ServerConfiguration conf = confByIndex(0); - conf.setUseHostNameAsBookieID(true); - - BookieShell bkShell = - new BookieShell(LedgerIdFormatter.LONG_LEDGERID_FORMATTER, EntryFormatter.STRING_FORMATTER); - bkShell.setConf(conf); - - assertEquals("Failed to return exit code!", 0, bkShell.run(argv)); - - } - - private LedgerHandle createLedgerWithEntries(BookKeeper bk, int numOfEntries) throws Exception { - LedgerHandle lh = bk.createLedger(1, 1, digestType, PASSWORD.getBytes()); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - final CountDownLatch latch = new CountDownLatch(numOfEntries); - - final AddCallback cb = new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - latch.countDown(); - } - }; - for (int i = 0; i < numOfEntries; i++) { - lh.asyncAddEntry(("foobar" + i).getBytes(), cb, null); - } - if (!latch.await(30, TimeUnit.SECONDS)) { - throw new Exception("Entries took too long to add"); - } - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - return lh; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerHandleAdapter.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerHandleAdapter.java deleted file mode 100644 index 086e9f330c5..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerHandleAdapter.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import io.netty.buffer.ByteBuf; -import org.apache.bookkeeper.proto.MockBookieClient; - -/** - * Adapter for tests to get the public access from LedgerHandle for its default - * scope. - */ -public class LedgerHandleAdapter { - - public static ByteBuf toSend(LedgerHandle lh, long entryId, ByteBuf data) { - return MockBookieClient.copyData(lh.getDigestManager() - .computeDigestAndPackageForSending(entryId, lh.getLastAddConfirmed(), - lh.addToLength(data.readableBytes()), data, new byte[20], 0)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java deleted file mode 100644 index 4444dd5b767..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.util.Base64; -import java.util.Collections; -import java.util.List; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.junit.Test; - -/** - * Unit test for ledger metadata. - */ -public class LedgerMetadataTest { - - private static final byte[] passwd = "testPasswd".getBytes(UTF_8); - - @Test - public void testGetters() { - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId()); - org.apache.bookkeeper.client.api.LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(1) - .withDigestType(DigestType.CRC32.toApiDigestType()).withPassword(passwd) - .newEnsembleEntry(0L, ensemble) - .withId(100L) - .build(); - - assertEquals(100L, metadata.getLedgerId()); - assertEquals(3, metadata.getEnsembleSize()); - assertEquals(2, metadata.getWriteQuorumSize()); - assertEquals(1, metadata.getAckQuorumSize()); - assertEquals(org.apache.bookkeeper.client.api.DigestType.CRC32, metadata.getDigestType()); - assertEquals(Collections.emptyMap(), metadata.getCustomMetadata()); - assertEquals(-1L, metadata.getCtime()); - assertEquals(-1L, metadata.getLastEntryId()); - assertEquals(0, metadata.getLength()); - assertFalse(metadata.isClosed()); - assertEquals(1, metadata.getAllEnsembles().size()); - assertEquals(ensemble, metadata.getAllEnsembles().get(0L)); - assertEquals(ensemble, metadata.getEnsembleAt(99L)); - } - - @Test - public void testToString() { - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId()); - - LedgerMetadata lm1 = LedgerMetadataBuilder.create() - .withDigestType(DigestType.CRC32.toApiDigestType()) - .withPassword(passwd) - .newEnsembleEntry(0L, ensemble) - .withId(100L) - .build(); - - assertTrue("toString should contain password value", - lm1.toString().contains(Base64.getEncoder().encodeToString(passwd))); - assertTrue("toSafeString should not contain password value", lm1.toSafeString().contains("OMITTED")); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecovery2Test.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecovery2Test.java deleted file mode 100644 index 59025f42f3b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecovery2Test.java +++ /dev/null @@ -1,581 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import com.google.common.collect.Lists; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallbackFuture; -import org.apache.bookkeeper.proto.MockBookies; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Ledger recovery tests using mocks rather than a real cluster. - */ -public class LedgerRecovery2Test { - private static final Logger log = LoggerFactory.getLogger(LedgerRecovery2Test.class); - - private static final byte[] PASSWD = "foobar".getBytes(); - private static final BookieId b1 = new BookieSocketAddress("b1", 3181).toBookieId(); - private static final BookieId b2 = new BookieSocketAddress("b2", 3181).toBookieId(); - private static final BookieId b3 = new BookieSocketAddress("b3", 3181).toBookieId(); - private static final BookieId b4 = new BookieSocketAddress("b4", 3181).toBookieId(); - private static final BookieId b5 = new BookieSocketAddress("b5", 3181).toBookieId(); - - private static Versioned setupLedger(ClientContext clientCtx, long ledgerId, - List bookies) throws Exception { - LedgerMetadata md = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(PASSWD).withDigestType(DigestType.CRC32C) - .withWriteQuorumSize(bookies.size()) - .newEnsembleEntry(0, bookies).build(); - return clientCtx.getLedgerManager().createLedgerMetadata(ledgerId, md).get(); - } - - private static Versioned setupLedger(ClientContext clientCtx, long ledgerId, - List bookies, - int ensembleSize, - int writeQuorumSize, - int ackQuorumSize) throws Exception { - LedgerMetadata md = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withPassword(PASSWD).withDigestType(DigestType.CRC32C) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0, bookies).build(); - return clientCtx.getLedgerManager().createLedgerMetadata(ledgerId, md).get(); - } - - - @Test - public void testCantRecoverAllDown() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - - Versioned md = setupLedger(clientCtx, 1L, Lists.newArrayList(b1, b2, b3)); - - clientCtx.getMockBookieClient().errorBookies(b1, b2, b3); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - try { - GenericCallbackFuture promise = new GenericCallbackFuture<>(); - lh.recover(promise, null, false); - promise.get(); - Assert.fail("Recovery shouldn't have been able to complete"); - } catch (ExecutionException ee) { - Assert.assertEquals(BKException.BKReadException.class, ee.getCause().getClass()); - } - } - - @Test - public void testCanReadLacButCantWrite() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - - Versioned md = setupLedger(clientCtx, 1, Lists.newArrayList(b1, b2, b3)); - - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 0L, -1L); - clientCtx.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> FutureUtils.exception(new BKException.BKWriteException())); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - try { - GenericCallbackFuture promise = new GenericCallbackFuture<>(); - lh.recover(promise, null, false); - promise.get(); - Assert.fail("Recovery shouldn't have been able to complete"); - } catch (ExecutionException ee) { - Assert.assertEquals(BKException.BKNotEnoughBookiesException.class, ee.getCause().getClass()); - } - } - - @Test - public void testMetadataClosedDuringRecovery() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - - Versioned md = setupLedger(clientCtx, 1, Lists.newArrayList(b1, b2, b3)); - - CompletableFuture writingBack = new CompletableFuture<>(); - CompletableFuture blocker = new CompletableFuture<>(); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 0L, -1L); - // will block recovery at the writeback phase - clientCtx.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> { - writingBack.complete(null); - return blocker; - }); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - - GenericCallbackFuture recoveryPromise = new GenericCallbackFuture<>(); - lh.recover(recoveryPromise, null, false); - - writingBack.get(10, TimeUnit.SECONDS); - - ClientUtil.transformMetadata(clientCtx, 1L, - (metadata) -> LedgerMetadataBuilder.from(metadata) - .withClosedState().withLastEntryId(-1).withLength(0).build()); - - // allow recovery to continue - blocker.complete(null); - - recoveryPromise.get(); - - Assert.assertEquals(lh.getLastAddConfirmed(), -1); - Assert.assertEquals(lh.getLength(), 0); - } - - @Test - public void testNewEnsembleAddedDuringRecovery() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - - Versioned md = setupLedger(clientCtx, 1, Lists.newArrayList(b1, b2, b3)); - - CompletableFuture writingBack = new CompletableFuture<>(); - CompletableFuture blocker = new CompletableFuture<>(); - CompletableFuture failing = new CompletableFuture<>(); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 0L, -1L); - // will block recovery at the writeback phase - clientCtx.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> { - writingBack.complete(null); - if (bookie.equals(b3)) { - return failing; - } else { - return blocker; - } - }); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - - GenericCallbackFuture recoveryPromise = new GenericCallbackFuture<>(); - lh.recover(recoveryPromise, null, false); - - writingBack.get(10, TimeUnit.SECONDS); - - ClientUtil.transformMetadata(clientCtx, 1L, - (metadata) -> LedgerMetadataBuilder.from(metadata).newEnsembleEntry(1L, Lists.newArrayList(b1, b2, b4)) - .build()); - - // allow recovery to continue - failing.completeExceptionally(new BKException.BKWriteException()); - blocker.complete(null); - - try { - recoveryPromise.get(); - Assert.fail("Should fail on the update"); - } catch (ExecutionException ee) { - Assert.assertEquals(BKException.BKUnexpectedConditionException.class, ee.getCause().getClass()); - } - } - - @Test - public void testRecoveryBookieFailedAtStart() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - - Versioned md = setupLedger(clientCtx, 1, Lists.newArrayList(b1, b2, b3)); - - CompletableFuture writingBack = new CompletableFuture<>(); - CompletableFuture blocker = new CompletableFuture<>(); - CompletableFuture failing = new CompletableFuture<>(); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 0L, -1L); - clientCtx.getMockBookieClient().errorBookies(b2); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - - GenericCallbackFuture recoveryPromise = new GenericCallbackFuture<>(); - lh.recover(recoveryPromise, null, false); - recoveryPromise.get(); - - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), - Lists.newArrayList(b1, b4, b3)); - } - - @Test - public void testRecoveryOneBookieFailsDuring() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - - Versioned md = setupLedger(clientCtx, 1, Lists.newArrayList(b1, b2, b3)); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 0L, -1L); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b3, 1L, 1L, -1L); - clientCtx.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> { - if (bookie.equals(b2) && entryId == 1L) { - return FutureUtils.exception(new BKException.BKWriteException()); - } else { - return FutureUtils.value(null); - } - }); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - - GenericCallbackFuture recoveryPromise = new GenericCallbackFuture<>(); - lh.recover(recoveryPromise, null, false); - recoveryPromise.get(); - - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 2); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(0L), - Lists.newArrayList(b1, b2, b3)); - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().get(1L), - Lists.newArrayList(b1, b4, b3)); - Assert.assertEquals(lh.getLastAddConfirmed(), 1L); - } - - @Test - public void testRecoveryTwoBookiesFailOnSameEntry() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - clientCtx.getMockRegistrationClient().addBookies(b4, b5).get(); - - Versioned md = setupLedger(clientCtx, 1, Lists.newArrayList(b1, b2, b3)); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 0L, -1L); - clientCtx.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> { - if (bookie.equals(b1) || bookie.equals(b2)) { - return FutureUtils.exception(new BKException.BKWriteException()); - } else { - return FutureUtils.value(null); - } - }); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - - GenericCallbackFuture recoveryPromise = new GenericCallbackFuture<>(); - lh.recover(recoveryPromise, null, false); - recoveryPromise.get(); - - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 1); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b3)); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b4)); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b5)); - Assert.assertEquals(lh.getLastAddConfirmed(), 0L); - } - - /** - * This test verifies the fix for the data loss scenario found by the TLA+ specfication, specifically - * the invariant violation that metadata and writer can diverge. The scenario is that the original writer - * can commit an entry e that will later be lost because a second writer can close the ledger at e-1. - * The cause is that fencing was originally only performed on LAC reads which is not enough to prevent - * the 1st writer from reaching Ack Quorum after the 2nd writer has closed the ledger. The fix has - * been to fence on recovery reads also. - */ - @Test - public void testFirstWriterCannotCommitWriteAfter2ndWriterCloses() throws Exception { - /* - This test uses CompletableFutures to control the sequence of actions performed by - two writers. There are different sets of futures: - - block*: These futures block the various reads, writes and metadata updates until the - test thread is ready for them to be executed. Thus ensuring the right sequence - of events occur. - - reachedStepN: These futures block in the test thread to ensure that we only unblock - an action when the prior one has been executed and we are already blocked - on the next actionin the sequence. - */ - - // Setup w1 - CompletableFuture reachedStep1 = new CompletableFuture<>(); - CompletableFuture reachedStep2 = new CompletableFuture<>(); - CompletableFuture reachedStep3 = new CompletableFuture<>(); - CompletableFuture reachedStep4 = new CompletableFuture<>(); - CompletableFuture reachedStep5 = new CompletableFuture<>(); - CompletableFuture reachedStep6 = new CompletableFuture<>(); - CompletableFuture reachedStep7 = new CompletableFuture<>(); - CompletableFuture reachedStep8 = new CompletableFuture<>(); - CompletableFuture reachedStep9 = new CompletableFuture<>(); - - MockBookies mockBookies = new MockBookies(); - MockClientContext clientCtx1 = MockClientContext.create(mockBookies); - Versioned md1 = setupLedger(clientCtx1, 1, Lists.newArrayList(b1, b2, b3)); - - CompletableFuture blockB1Write = new CompletableFuture<>(); - CompletableFuture blockB2Write = new CompletableFuture<>(); - CompletableFuture blockB3Write = new CompletableFuture<>(); - clientCtx1.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> { - // ignore seed entries e0 and e1 - if (entryId < 2) { - return FutureUtils.value(null); - } - - if (!reachedStep1.isDone()) { - reachedStep1.complete(null); - } - - if (bookie.equals(b1)) { - return blockB1Write; - } else if (bookie.equals(b2)) { - reachedStep9.complete(null); - return blockB2Write; - } else if (bookie.equals(b3)) { - reachedStep3.complete(null); - return blockB3Write; - } else { - return FutureUtils.value(null); - } - }); - - LedgerHandle w1 = new LedgerHandle(clientCtx1, 1, md1, - BookKeeper.DigestType.CRC32C, - ClientUtil.PASSWD, WriteFlag.NONE); - w1.addEntry("e0".getBytes(StandardCharsets.UTF_8)); - w1.addEntry("e1".getBytes(StandardCharsets.UTF_8)); - - // Setup w2 - MockClientContext clientCtx2 = MockClientContext.create(mockBookies); - Versioned md2 = setupLedger(clientCtx2, 1, Lists.newArrayList(b1, b2, b3)); - - CompletableFuture blockB1ReadLac = new CompletableFuture<>(); - CompletableFuture blockB2ReadLac = new CompletableFuture<>(); - CompletableFuture blockB3ReadLac = new CompletableFuture<>(); - - CompletableFuture blockB1ReadEntry0 = new CompletableFuture<>(); - CompletableFuture blockB2ReadEntry0 = new CompletableFuture<>(); - CompletableFuture blockB3ReadEntry0 = new CompletableFuture<>(); - - AtomicBoolean isB1LacRead = new AtomicBoolean(true); - AtomicBoolean isB2LacRead = new AtomicBoolean(true); - AtomicBoolean isB3LacRead = new AtomicBoolean(true); - - clientCtx2.getMockBookieClient().setPreReadHook( - (bookie, ledgerId, entryId) -> { - if (bookie.equals(b1)) { - if (isB1LacRead.get()) { - isB1LacRead.set(false); - reachedStep2.complete(null); - return blockB1ReadLac; - } else { - reachedStep6.complete(null); - return blockB1ReadEntry0; - } - } else if (bookie.equals(b2)) { - if (isB2LacRead.get()) { - try { - isB2LacRead.set(false); - reachedStep4.complete(null); - blockB2ReadLac.get(); // block this read - it does not succeed - } catch (Throwable t){} - return FutureUtils.exception(new BKException.BKWriteException()); - } else { - reachedStep7.complete(null); - return blockB2ReadEntry0; - } - } else if (bookie.equals(b3)) { - if (isB3LacRead.get()) { - isB3LacRead.set(false); - reachedStep5.complete(null); - return blockB3ReadLac; - } else { - return blockB3ReadEntry0; - } - } else { - return FutureUtils.value(null); - } - }); - - AtomicInteger w2MetaUpdates = new AtomicInteger(0); - CompletableFuture blockW2StartingRecovery = new CompletableFuture<>(); - CompletableFuture blockW2ClosingLedger = new CompletableFuture<>(); - clientCtx2.getMockLedgerManager().setPreWriteHook((ledgerId, metadata) -> { - if (w2MetaUpdates.get() == 0) { - w2MetaUpdates.incrementAndGet(); - return blockW2StartingRecovery; - } else { - reachedStep8.complete(null); - return blockW2ClosingLedger; - } - }); - - ReadOnlyLedgerHandle w2 = new ReadOnlyLedgerHandle( - clientCtx2, 1L, md2, BookKeeper.DigestType.CRC32C, PASSWD, false); - - // Start an async add entry, blocked for now. - CompletableFuture w1WriteFuture = new CompletableFuture<>(); - AtomicInteger writeResult = new AtomicInteger(0); - w1.asyncAddEntry("e2".getBytes(), (int rc, LedgerHandle lh1, long entryId, Object ctx) -> { - if (rc == BKException.Code.OK) { - writeResult.set(1); - } else { - writeResult.set(2); - } - SyncCallbackUtils.finish(rc, null, w1WriteFuture); - }, null); - - // Step 1. w2 starts recovery - stepBlock(reachedStep1); - GenericCallbackFuture recoveryPromise = new GenericCallbackFuture<>(); - w2.recover(recoveryPromise, null, false); - blockW2StartingRecovery.complete(null); - - // Step 2. w2 fencing read LAC reaches B1 - stepBlock(reachedStep2); - blockB1ReadLac.complete(null); - - // Step 3. w1 add e0 reaches B3 - stepBlock(reachedStep3); - blockB3Write.complete(null); - - // Step 4. w2 fencing LAC read does not reach B2 or it fails - stepBlock(reachedStep4); - blockB2ReadLac.complete(null); - - // Step 5. w2 fencing LAC read reaches B3 - stepBlock(reachedStep5); - blockB3ReadLac.complete(null); - - // Step 6. w2 sends read e0 to b1, gets NoSuchLedger - stepBlock(reachedStep6); - blockB1ReadEntry0.complete(null); - - // Step 7. w2 send read e0 to b2, gets NoSuchLedger - stepBlock(reachedStep7); - blockB2ReadEntry0.complete(null); - - // Step 8. w2 closes ledger because (Qw-Qa)+1 bookies confirmed they do not have it - // last entry id set to 0 - stepBlock(reachedStep8); - blockW2ClosingLedger.complete(null); - - // Step 9. w1 add e0 reaches b2 (which was fenced by a recovery read) - stepBlock(reachedStep9); - blockB2Write.complete(null); - - // Step 10. w1 write fails to reach AckQuorum - try { - w1WriteFuture.get(200, TimeUnit.MILLISECONDS); - Assert.fail("The write to b2 should have failed as it was fenced by the recovery read of step 7"); - } catch (ExecutionException e) { - Assert.assertTrue(e.getCause() instanceof BKException.BKLedgerFencedException); - } - - // w1 received negative acknowledgement of e2 being written - Assert.assertEquals(1, w1.getLedgerMetadata().getAllEnsembles().size()); - Assert.assertEquals(2, writeResult.get()); - Assert.assertEquals(1L, w1.getLastAddConfirmed()); - - // w2 closed the ledger with only the original entries, not the third one - // i.e there is no divergence between w1m, w2 and metadata - Assert.assertEquals(1, w2.getLedgerMetadata().getAllEnsembles().size()); - Assert.assertEquals(1L, w2.getLastAddConfirmed()); - } - - private void stepBlock(CompletableFuture reachedStepFuture) { - try { - reachedStepFuture.get(); - } catch (Exception e) {} - } - - - /* - * This test verifies that an IllegalStateException does not occur during recovery because of an attempt - * to create a new ensemble that has a lower first entry id than an existing ledger. - * - * To reproduce original issue, revert the fix and run this test. - * The fix was to apply max(LAC from current ensemble, (first entry of current ensemble - 1)) as the LAC - * of the recovery phase rather than accept a value of -1 that might be returned by the LAC reads. - */ - @Test - public void testRecoveryWhenSecondEnsembleReturnsLacMinusOne() throws Exception { - MockClientContext clientCtx = MockClientContext.create(); - clientCtx.getMockRegistrationClient().addBookies(b4).get(); - - // at least two non-empty ensembles required as else the first ensemble would - // only be replaced, thus avoiding the issue. - - // initial state: 2 ensembles due to a write failure of e1 to b2 - // ensemble 1 - Versioned md = setupLedger(clientCtx, 1, Lists.newArrayList(b1, b2), 2, 2, 2); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 0L, -1L); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b2, 1L, 0L, -1L); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b1, 1L, 1L, -1L); - // write to b2 failed, causing ensemble change - - // ensemble 2 - the write of e1 to b2 failed, so new ensemble with b3 created - ClientUtil.transformMetadata(clientCtx, 1L, - (metadata) -> LedgerMetadataBuilder.from(metadata).newEnsembleEntry(1L, Lists.newArrayList(b1, b3)) - .build()); - clientCtx.getMockBookieClient().getMockBookies().seedEntries(b3, 1L, 1L, 0L); - - ReadOnlyLedgerHandle lh = new ReadOnlyLedgerHandle( - clientCtx, 1L, md, BookKeeper.DigestType.CRC32C, PASSWD, false); - - // however, any read or write to b3 fails, which will: - // 1. cause the LAC read to return -1 (b1 has -1) - // 2. cause an ensemble change during recovery write back phase - clientCtx.getMockBookieClient().setPreWriteHook( - (bookie, ledgerId, entryId) -> { - if (bookie.equals(b3)) { - return FutureUtils.exception(new BKException.BKWriteException()); - } else { - return FutureUtils.value(null); - } - }); - - clientCtx.getMockBookieClient().setPreReadHook( - (bookie, ledgerId, entryId) -> { - if (bookie.equals(b3)) { - return FutureUtils.exception(new BKException.BKTimeoutException()); - } else { - return FutureUtils.value(null); - } - }); - - // writer 2 starts recovery (the subject of this test) - // (either the writer failed or simply has not yet sent the pending writes to the new ensemble) - GenericCallbackFuture recoveryPromise = new GenericCallbackFuture<>(); - lh.recover(recoveryPromise, null, false); - recoveryPromise.get(); - - // The recovery process is successfully able to complete recovery, with the expected ensembles. - Assert.assertEquals(lh.getLedgerMetadata().getAllEnsembles().size(), 2); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b1)); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(0L).contains(b2)); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(1L).contains(b1)); - Assert.assertTrue(lh.getLedgerMetadata().getAllEnsembles().get(1L).contains(b4)); - - // the ledger is closed with entry id 1 - Assert.assertEquals(lh.getLastAddConfirmed(), 1L); - Assert.assertEquals(lh.getLedgerMetadata().getLastEntryId(), 1L); - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecoveryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecoveryTest.java deleted file mode 100644 index 4a9e65a6534..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecoveryTest.java +++ /dev/null @@ -1,492 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.util.Enumeration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This unit test tests ledger recovery. - */ -public class LedgerRecoveryTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(LedgerRecoveryTest.class); - - private final DigestType digestType; - - public LedgerRecoveryTest() { - super(3); - this.digestType = DigestType.CRC32; - this.baseConf.setAllowEphemeralPorts(false); - } - - private void testInternal(int numEntries) throws Exception { - /* - * Create ledger. - */ - LedgerHandle beforelh = null; - beforelh = bkc.createLedger(digestType, "".getBytes()); - - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < numEntries; i++) { - beforelh.addEntry(tmp.getBytes()); - } - - long length = (long) (numEntries * tmp.length()); - - /* - * Try to open ledger. - */ - LedgerHandle afterlh = bkc.openLedger(beforelh.getId(), digestType, "".getBytes()); - - /* - * Check if has recovered properly. - */ - assertEquals("Has not recovered correctly", numEntries - 1, afterlh.getLastAddConfirmed()); - assertEquals("Has not set the length correctly", length, afterlh.getLength()); - } - - @Test - public void testLedgerRecovery() throws Exception { - testInternal(100); - - } - - @Test - public void testEmptyLedgerRecoveryOne() throws Exception { - testInternal(1); - } - - @Test - public void testEmptyLedgerRecovery() throws Exception { - testInternal(0); - } - - @Test - public void testLedgerRecoveryWithWrongPassword() throws Exception { - // Create a ledger - byte[] ledgerPassword = "aaaa".getBytes(); - LedgerHandle lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - long ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - String tmp = "BookKeeper is cool!"; - int numEntries = 30; - for (int i = 0; i < numEntries; i++) { - lh.addEntry(tmp.getBytes()); - } - - // Using wrong password - ledgerPassword = "bbbb".getBytes(); - try { - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - fail("Opening ledger with wrong password should fail"); - } catch (BKException e) { - // should failed - } - } - - @Test - public void testLedgerRecoveryWithNotEnoughBookies() throws Exception { - int numEntries = 3; - - // Create a ledger - LedgerHandle beforelh = null; - beforelh = bkc.createLedger(3, 3, digestType, "".getBytes()); - - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < numEntries; i++) { - beforelh.addEntry(tmp.getBytes()); - } - - // shutdown first bookie server - killBookie(0); - - /* - * Try to open ledger. - */ - try { - bkc.openLedger(beforelh.getId(), digestType, "".getBytes()); - fail("should not reach here!"); - } catch (Exception e) { - // should thrown recovery exception - } - - // start a new bookie server - startNewBookie(); - - LedgerHandle afterlh = bkc.openLedger(beforelh.getId(), digestType, "".getBytes()); - - /* - * Check if has recovered properly. - */ - assertEquals(numEntries - 1, afterlh.getLastAddConfirmed()); - } - - @Test - public void testLedgerRecoveryWithSlowBookie() throws Exception { - for (int i = 0; i < 3; i++) { - LOG.info("TestLedgerRecoveryWithAckQuorum @ slow bookie {}", i); - ledgerRecoveryWithSlowBookie(3, 3, 2, 1, i); - } - } - - private void ledgerRecoveryWithSlowBookie(int ensembleSize, int writeQuorumSize, - int ackQuorumSize, int numEntries, int slowBookieIdx) throws Exception { - - // Create a ledger - LedgerHandle beforelh = null; - beforelh = bkc.createLedger(ensembleSize, writeQuorumSize, ackQuorumSize, - digestType, "".getBytes()); - - // kill first bookie server to start a fake one to simulate a slow bookie - // and failed to add entry on crash - // until write succeed - BookieId host = beforelh.getCurrentEnsemble().get(slowBookieIdx); - ServerConfiguration conf = killBookie(host); - - Bookie fakeBookie = new TestBookieImpl(conf) { - @Override - public void addEntry(ByteBuf entry, boolean ackBeforeSync, WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException { - // drop request to simulate a slow and failed bookie - } - }; - startAndAddBookie(conf, fakeBookie); - - // avoid not-enough-bookies case - startNewBookie(); - - // write would still succeed with 2 bookies ack - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < numEntries; i++) { - beforelh.addEntry(tmp.getBytes()); - } - - conf = killBookie(host); - // the bookie goes normally - startAndAddBookie(conf); - - /* - * Try to open ledger. - */ - LedgerHandle afterlh = bkc.openLedger(beforelh.getId(), digestType, "".getBytes()); - - /* - * Check if has recovered properly. - */ - assertEquals(numEntries - 1, afterlh.getLastAddConfirmed()); - } - - /** - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-355} - * A recovery during a rolling restart shouldn't affect the ability - * to recovery the ledger later. - * We have a ledger on ensemble B1,B2,B3. - * The sequence of events is - * 1. B1 brought down for maintenance - * 2. Ledger recovery started - * 3. B2 answers read last confirmed. - * 4. B1 replaced in ensemble by B4 - * 5. Write to B4 fails for some reason - * 6. B1 comes back up. - * 7. B2 goes down for maintenance. - * 8. Ledger recovery starts (ledger is now unavailable) - */ - @Test - public void testLedgerRecoveryWithRollingRestart() throws Exception { - LedgerHandle lhbefore = bkc.createLedger(numBookies, 2, digestType, "".getBytes()); - for (int i = 0; i < (numBookies * 3) + 1; i++) { - lhbefore.addEntry("data".getBytes()); - } - - // Add a dead bookie to the cluster - ServerConfiguration conf = newServerConfiguration(); - Bookie deadBookie1 = new TestBookieImpl(conf) { - @Override - public void recoveryAddEntry(ByteBuf entry, WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException { - // drop request to simulate a slow and failed bookie - throw new IOException("Couldn't write for some reason"); - } - }; - startAndAddBookie(conf, deadBookie1); - - // kill first bookie server - BookieId bookie1 = lhbefore.getCurrentEnsemble().get(0); - ServerConfiguration conf1 = killBookie(bookie1); - - // Try to recover and fence the ledger after killing one bookie in the - // ensemble in the ensemble, and another bookie is available in zk, but not writtable - try { - bkc.openLedger(lhbefore.getId(), digestType, "".getBytes()); - fail("Shouldn't be able to open ledger, there should be entries missing"); - } catch (BKException.BKLedgerRecoveryException e) { - // expected - } - - // restart the first server, kill the second - startAndAddBookie(conf1); - BookieId bookie2 = lhbefore.getCurrentEnsemble().get(1); - ServerConfiguration conf2 = killBookie(bookie2); - - // using async, because this could trigger an assertion - final AtomicInteger returnCode = new AtomicInteger(0); - final CountDownLatch openLatch = new CountDownLatch(1); - bkc.asyncOpenLedger(lhbefore.getId(), digestType, "".getBytes(), - new AsyncCallback.OpenCallback() { - public void openComplete(int rc, LedgerHandle lh, Object ctx) { - returnCode.set(rc); - openLatch.countDown(); - if (rc == BKException.Code.OK) { - try { - lh.close(); - } catch (Exception e) { - LOG.error("Exception closing ledger handle", e); - } - } - } - }, null); - assertTrue("Open call should have completed", openLatch.await(5, TimeUnit.SECONDS)); - assertFalse("Open should not have succeeded", returnCode.get() == BKException.Code.OK); - - startAndAddBookie(conf2); - - LedgerHandle lhafter = bkc.openLedger(lhbefore.getId(), digestType, - "".getBytes()); - assertEquals("Fenced ledger should have correct lastAddConfirmed", - lhbefore.getLastAddConfirmed(), lhafter.getLastAddConfirmed()); - } - - /** - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-355} - * Verify that if a recovery happens with 1 replica missing, and it's replaced - * with a faulty bookie, it doesn't break future recovery from happening. - * 1. Ledger is created with quorum size as 2, and entries are written - * 2. Now first bookie is in the ensemble is brought down. - * 3. Another client fence and trying to recover the same ledger - * 4. During this time ensemble change will happen - * and new bookie will be added. But this bookie is not able to write. - * 5. This recovery will fail. - * 7. A new non-faulty bookie comes up - * 8. Another client trying to recover the same ledger. - */ - @Test - public void testBookieFailureDuringRecovery() throws Exception { - LedgerHandle lhbefore = bkc.createLedger(numBookies, 2, digestType, "".getBytes()); - for (int i = 0; i < (numBookies * 3) + 1; i++) { - lhbefore.addEntry("data".getBytes()); - } - - // Add a dead bookie to the cluster - ServerConfiguration conf = newServerConfiguration(); - Bookie deadBookie1 = new TestBookieImpl(conf) { - @Override - public void recoveryAddEntry(ByteBuf entry, WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException { - // drop request to simulate a slow and failed bookie - throw new IOException("Couldn't write for some reason"); - } - }; - startAndAddBookie(conf, deadBookie1); - - // kill first bookie server - BookieId bookie1 = lhbefore.getCurrentEnsemble().get(0); - killBookie(bookie1); - - // Try to recover and fence the ledger after killing one bookie in the - // ensemble in the ensemble, and another bookie is available in zk but not writtable - try { - bkc.openLedger(lhbefore.getId(), digestType, "".getBytes()); - fail("Shouldn't be able to open ledger, there should be entries missing"); - } catch (BKException.BKLedgerRecoveryException e) { - // expected - } - - // start a new good server - startNewBookie(); - LedgerHandle lhafter = bkc.openLedger(lhbefore.getId(), digestType, - "".getBytes()); - assertEquals("Fenced ledger should have correct lastAddConfirmed", - lhbefore.getLastAddConfirmed(), lhafter.getLastAddConfirmed()); - } - - /** - * Verify that it doesn't break the recovery when changing ensemble in - * recovery add. - */ - @Test - public void testEnsembleChangeDuringRecovery() throws Exception { - LedgerHandle lh = bkc.createLedger(numBookies, 2, 2, digestType, "".getBytes()); - int numEntries = (numBookies * 3) + 1; - final AtomicInteger numPendingAdds = new AtomicInteger(numEntries); - final CountDownLatch addDone = new CountDownLatch(1); - for (int i = 0; i < numEntries; i++) { - lh.asyncAddEntry("data".getBytes(), new AddCallback() { - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - if (BKException.Code.OK != rc) { - addDone.countDown(); - return; - } - if (numPendingAdds.decrementAndGet() == 0) { - addDone.countDown(); - } - } - - }, null); - } - addDone.await(10, TimeUnit.SECONDS); - if (numPendingAdds.get() > 0) { - fail("Failed to add " + numEntries + " to ledger handle " + lh.getId()); - } - // kill first 2 bookies to replace bookies - BookieId bookie1 = lh.getCurrentEnsemble().get(0); - ServerConfiguration conf1 = killBookie(bookie1); - BookieId bookie2 = lh.getCurrentEnsemble().get(1); - ServerConfiguration conf2 = killBookie(bookie2); - - // replace these two bookies - startDeadBookie(conf1); - startDeadBookie(conf2); - // kick in two brand new bookies - startNewBookie(); - startNewBookie(); - - // two dead bookies are put in the ensemble which would cause ensemble - // change - LedgerHandle recoveredLh = bkc.openLedger(lh.getId(), digestType, "".getBytes()); - assertEquals("Fenced ledger should have correct lastAddConfirmed", lh.getLastAddConfirmed(), - recoveredLh.getLastAddConfirmed()); - } - - private void startDeadBookie(ServerConfiguration conf) throws Exception { - Bookie rBookie = new TestBookieImpl(conf) { - @Override - public void recoveryAddEntry(ByteBuf entry, WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException { - // drop request to simulate a dead bookie - throw new IOException("Couldn't write entries for some reason"); - } - }; - startAndAddBookie(conf, rBookie); - } - - @Test - public void testBatchRecoverySize3() throws Exception { - batchRecovery(3); - } - - @Test - public void testBatchRecoverySize13() throws Exception { - batchRecovery(13); - } - - private void batchRecovery(int batchSize) throws Exception { - ClientConfiguration newConf = new ClientConfiguration() - .setReadEntryTimeout(60000) - .setAddEntryTimeout(60000) - .setEnableParallelRecoveryRead(false) - .setRecoveryReadBatchSize(batchSize); - - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper newBk = new BookKeeper(newConf); - - LedgerHandle lh = newBk.createLedger(numBookies, 2, 2, digestType, "".getBytes()); - - CountDownLatch latch1 = new CountDownLatch(1); - CountDownLatch latch2 = new CountDownLatch(1); - sleepBookie(lh.getCurrentEnsemble().get(0), latch1); - sleepBookie(lh.getCurrentEnsemble().get(1), latch2); - - int numEntries = (numBookies * 3) + 1; - final AtomicInteger numPendingAdds = new AtomicInteger(numEntries); - final CountDownLatch addDone = new CountDownLatch(1); - for (int i = 0; i < numEntries; i++) { - lh.asyncAddEntry(("" + i).getBytes(), new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - if (BKException.Code.OK != rc) { - addDone.countDown(); - return; - } - if (numPendingAdds.decrementAndGet() == 0) { - addDone.countDown(); - } - } - }, null); - } - latch1.countDown(); - latch2.countDown(); - addDone.await(10, TimeUnit.SECONDS); - assertEquals(0, numPendingAdds.get()); - - LedgerHandle recoverLh = newBk.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(BookieProtocol.INVALID_ENTRY_ID, recoverLh.getLastAddConfirmed()); - - MockClientContext parallelReadCtx = MockClientContext.copyOf(bkc.getClientCtx()) - .setConf(ClientInternalConf.fromConfig(newConf.setEnableParallelRecoveryRead(true))); - - LedgerRecoveryOp recoveryOp = new LedgerRecoveryOp(recoverLh, parallelReadCtx); - CompletableFuture f = recoveryOp.initiate(); - f.get(10, TimeUnit.SECONDS); - - assertEquals(numEntries, recoveryOp.readCount.get()); - assertEquals(numEntries, recoveryOp.writeCount.get()); - - Enumeration enumeration = recoverLh.readEntries(0, numEntries - 1); - - int numReads = 0; - while (enumeration.hasMoreElements()) { - LedgerEntry entry = enumeration.nextElement(); - assertEquals((long) numReads, entry.getEntryId()); - assertEquals(numReads, Integer.parseInt(new String(entry.getEntry()))); - ++numReads; - } - assertEquals(numEntries, numReads); - - newBk.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ListLedgersTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ListLedgersTest.java deleted file mode 100644 index 8bb23684bc7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ListLedgersTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Iterator; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Test ListLedgers. - */ -public class ListLedgersTest extends BookKeeperClusterTestCase { - - private final DigestType digestType; - - public ListLedgersTest () { - super(4); - this.digestType = DigestType.CRC32; - } - - @Test - public void testListLedgers() - throws Exception { - int numOfLedgers = 10; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - for (int i = 0; i < numOfLedgers; i++) { - bkc.createLedger(digestType, "testPasswd". - getBytes()).close(); - } - - BookKeeperAdmin admin = new BookKeeperAdmin(zkUtil. - getZooKeeperConnectString()); - Iterable iterable = admin.listLedgers(); - - int counter = 0; - for (Long lId: iterable) { - counter++; - } - - assertTrue("Wrong number of ledgers: " + numOfLedgers, - counter == numOfLedgers); - } - - @Test - public void testEmptyList() - throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeperAdmin admin = new BookKeeperAdmin(zkUtil. - getZooKeeperConnectString()); - Iterable iterable = admin.listLedgers(); - - assertFalse("There should be no ledger", iterable.iterator().hasNext()); - } - - @Test - public void testRemoveNotSupported() - throws Exception { - int numOfLedgers = 1; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - for (int i = 0; i < numOfLedgers; i++) { - bkc.createLedger(digestType, "testPasswd". - getBytes()).close(); - } - - BookKeeperAdmin admin = new BookKeeperAdmin(zkUtil. - getZooKeeperConnectString()); - Iterator iterator = admin.listLedgers().iterator(); - iterator.next(); - try { - iterator.remove(); - } catch (UnsupportedOperationException e) { - // This exception is expected - return; - } - - fail("Remove is not supported, we shouln't have reached this point"); - - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MdcContextTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MdcContextTest.java deleted file mode 100644 index 2a7a15ca253..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MdcContextTest.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.client; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasItem; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.AdditionalAnswers.answerVoid; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; - -import java.io.File; -import java.util.Queue; -import java.util.UUID; -import java.util.concurrent.ConcurrentLinkedQueue; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.NullAppender; -import org.hamcrest.CoreMatchers; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - - -/** - * Test passing of MDC context. - */ -@SuppressWarnings("deprecation") -@Slf4j -public class MdcContextTest extends BookKeeperClusterTestCase { - public static final String MDC_REQUEST_ID = "request_id"; - - final byte[] entry = "Test Entry".getBytes(); - - BookKeeper bkc; - LedgerHandle lh; - - private NullAppender mockAppender; - private Queue capturedEvents; - - public MdcContextTest() { - super(3); - baseConf.setNumAddWorkerThreads(0); - baseConf.setNumReadWorkerThreads(0); - baseConf.setPreserveMdcForTaskExecution(true); - baseConf.setReadOnlyModeEnabled(true); - - // for read-only bookie - baseConf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - baseConf.setEntryLogFilePreAllocationEnabled(false); - baseConf.setMinUsableSizeForEntryLogCreation(Long.MAX_VALUE); - } - - - public static String mdcFormat(Object mdc, String message) { - return mdc == null - ? "[" + MDC_REQUEST_ID + ":] - " + message - : "[" + MDC_REQUEST_ID + ":" + mdc - + "] - " + message; - } - - public void assertLogWithMdc(String mdc, String msgSubstring) { - assertThat(capturedEvents, - hasItem(CoreMatchers.allOf( - containsString("[" + MDC_REQUEST_ID + ":" + mdc + "] - "), - containsString(msgSubstring) - ))); - } - - @Before - public void setUp() throws Exception { - super.setUp(); - ClientConfiguration conf = new ClientConfiguration(); - conf.setReadTimeout(360) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()) - .setPreserveMdcForTaskExecution(true); - - ThreadContext.clearMap(); - bkc = new BookKeeper(conf); - - ThreadContext.put(MDC_REQUEST_ID, "ledger_create"); - log.info("creating ledger"); - lh = bkc.createLedgerAdv(3, 3, 3, BookKeeper.DigestType.CRC32, new byte[] {}); - ThreadContext.clearMap(); - - LoggerContext lc = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); - mockAppender = spy(NullAppender.createAppender(UUID.randomUUID().toString())); - mockAppender.start(); - lc.getConfiguration().addAppender(mockAppender); - lc.getRootLogger().addAppender(lc.getConfiguration().getAppender(mockAppender.getName())); - lc.getConfiguration().getRootLogger().setLevel(org.apache.logging.log4j.Level.INFO); - lc.updateLoggers(); - - capturedEvents = new ConcurrentLinkedQueue<>(); - - doAnswer(answerVoid((LogEvent event) -> capturedEvents.add( - mdcFormat(event.getContextData().getValue(MDC_REQUEST_ID), event.getMessage().getFormattedMessage()) - ))).when(mockAppender).append(any()); - } - - @After - public void tearDown() throws Exception { - lh.close(); - bkc.close(); - LoggerContext lc = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); - lc.getRootLogger().removeAppender(lc.getConfiguration().getAppender(mockAppender.getName())); - lc.updateLoggers(); - capturedEvents = null; - ThreadContext.clearMap(); - super.tearDown(); - } - - @Test - public void testLedgerCreateFails() throws Exception { - ThreadContext.put(MDC_REQUEST_ID, "ledger_create_fail"); - try { - bkc.createLedgerAdv(99, 3, 2, BookKeeper.DigestType.CRC32, new byte[]{}); - Assert.fail("should not get here"); - } catch (BKException bke) { - // expected - } - assertLogWithMdc("ledger_create_fail", "Not enough bookies to create ledger"); - } - - @Test - public void testSimpleAdd() throws Exception { - ThreadContext.put(MDC_REQUEST_ID, "ledger_add_entry"); - lh.addEntry(0, entry); - - // client msg - assertLogWithMdc("ledger_add_entry", "Successfully connected to bookie"); - // bookie msg - assertLogWithMdc("ledger_add_entry", "Created new entry log file"); - } - - @Test - public void testAddWithEnsembleChange() throws Exception { - lh.addEntry(0, entry); - startNewBookie(); - killBookie(0); - - ThreadContext.put(MDC_REQUEST_ID, "ledger_add_entry"); - lh.addEntry(1, entry); - assertLogWithMdc("ledger_add_entry", "Could not connect to bookie"); - assertLogWithMdc("ledger_add_entry", "Failed to write entry"); - //commented out until we figure out a way to preserve MDC through a call out - //to another thread pool - //assertLogWithMdc("ledger_add_entry", "New Ensemble"); - } - - @Test - public void testAddFailsWithReadOnlyBookie() throws Exception { - for (int i = 0; i < 3; ++i) { - Bookie bookie = serverByIndex(i).getBookie(); - File[] ledgerDirs = confByIndex(i).getLedgerDirs(); - LedgerDirsManager ledgerDirsManager = ((BookieImpl) bookie).getLedgerDirsManager(); - ledgerDirsManager.addToFilledDirs(new File(ledgerDirs[0], "current")); - } - - ThreadContext.put(MDC_REQUEST_ID, "ledger_add_entry"); - try { - lh.addEntry(0, entry); - Assert.fail("should not get here"); - } catch (BKException bke) { - // expected, pass - } - - assertLogWithMdc("ledger_add_entry", "No writable ledger dirs below diskUsageThreshold"); - assertLogWithMdc("ledger_add_entry", "All ledger directories are non writable and no reserved space"); - assertLogWithMdc("ledger_add_entry", "Error writing entry:0 to ledger:0"); - assertLogWithMdc("ledger_add_entry", "Add for failed on bookie"); - assertLogWithMdc("ledger_add_entry", "Failed to find 1 bookies"); - assertLogWithMdc("ledger_add_entry", "Closing ledger 0 due to NotEnoughBookiesException"); - } - - @Test - public void testAddFailsDuplicateEntry() throws Exception { - lh.addEntry(0, entry); - - ThreadContext.put(MDC_REQUEST_ID, "ledger_add_duplicate_entry"); - try { - lh.addEntry(0, entry); - Assert.fail("should not get here"); - } catch (BKException bke) { - // expected, pass - } - - assertLogWithMdc("ledger_add_duplicate_entry", "Trying to re-add duplicate entryid:0"); - assertLogWithMdc("ledger_add_duplicate_entry", "Write of ledger entry to quorum failed"); - } - - @Test - public void testReadEntryBeyondLac() throws Exception { - ThreadContext.put(MDC_REQUEST_ID, "ledger_read_entry"); - - try { - lh.readEntries(100, 100); - fail("should not get here"); - } catch (BKException.BKReadException e) { - // pass - } - assertLogWithMdc("ledger_read_entry", "ReadEntries exception on ledgerId:0 firstEntry:100 lastEntry:100"); - } - - @Test - public void testReadFromDeletedLedger() throws Exception { - lh.addEntry(0, entry); - lh.close(); - bkc.deleteLedger(lh.ledgerId); - - ThreadContext.put(MDC_REQUEST_ID, "ledger_read_entry"); - - try { - lh.readEntries(100, 100); - fail("should not get here"); - } catch (BKException.BKReadException e) { - // pass - } - assertLogWithMdc("ledger_read_entry", "ReadEntries exception on ledgerId:0 firstEntry:100 lastEntry:100"); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MetadataUpdateLoopTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MetadataUpdateLoopTest.java deleted file mode 100644 index 5b7db179b10..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MetadataUpdateLoopTest.java +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import lombok.AllArgsConstructor; -import lombok.Data; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.MockLedgerManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.lang3.tuple.Triple; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test metadata update loop. - */ -public class MetadataUpdateLoopTest { - static final Logger LOG = LoggerFactory.getLogger(MetadataUpdateLoopTest.class); - - /** - * Test that we can update the metadata using the update loop. - */ - @Test - public void testBasicUpdate() throws Exception { - try (LedgerManager lm = new MockLedgerManager()) { - long ledgerId = 1234L; - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withEnsembleSize(5) - .withDigestType(DigestType.CRC32C).withPassword(new byte[0]) - .newEnsembleEntry(0L, Lists.newArrayList(BookieId.parse("0.0.0.0:3181"), - BookieId.parse("0.0.0.1:3181"), - BookieId.parse("0.0.0.2:3181"), - BookieId.parse("0.0.0.3:3181"), - BookieId.parse("0.0.0.4:3181"))).build(); - - Versioned writtenMetadata = lm.createLedgerMetadata(ledgerId, initMeta).get(); - - AtomicReference> reference = new AtomicReference<>(writtenMetadata); - - BookieId newAddress = BookieId.parse("0.0.0.5:3181"); - MetadataUpdateLoop loop = new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> true, - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(0, newAddress); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference::compareAndSet); - loop.run().get(); - - Assert.assertNotEquals(reference.get(), writtenMetadata); - Assert.assertEquals(reference.get().getValue().getEnsembleAt(0L).get(0), newAddress); - } - } - - /** - * Test that when 2 update loops conflict when making diffent updates to the metadata, - * both will eventually succeed, and both updates will be reflected in the final metadata. - */ - @Test - public void testConflictOnWrite() throws Exception { - try (BlockableMockLedgerManager lm = spy(new BlockableMockLedgerManager())) { - lm.blockWrites(); - - long ledgerId = 1234L; - BookieId b0 = BookieId.parse("0.0.0.0:3181"); - BookieId b1 = BookieId.parse("0.0.0.1:3181"); - BookieId b2 = BookieId.parse("0.0.0.2:3181"); - BookieId b3 = BookieId.parse("0.0.0.3:3181"); - - LedgerMetadata initMeta = LedgerMetadataBuilder.create().withEnsembleSize(2).withId(ledgerId) - .withDigestType(DigestType.CRC32C).withPassword(new byte[0]) - .withWriteQuorumSize(2).newEnsembleEntry(0L, Lists.newArrayList(b0, b1)).build(); - Versioned writtenMetadata = - lm.createLedgerMetadata(ledgerId, initMeta).get(); - - AtomicReference> reference1 = new AtomicReference<>(writtenMetadata); - CompletableFuture> loop1 = new MetadataUpdateLoop( - lm, - ledgerId, - reference1::get, - (currentMetadata) -> currentMetadata.getEnsembleAt(0L).contains(b0), - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(0, b2); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference1::compareAndSet).run(); - - AtomicReference> reference2 = new AtomicReference<>(writtenMetadata); - CompletableFuture> loop2 = new MetadataUpdateLoop( - lm, - ledgerId, - reference2::get, - (currentMetadata) -> currentMetadata.getEnsembleAt(0L).contains(b1), - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(1, b3); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference2::compareAndSet).run(); - - lm.releaseWrites(); - - Versioned l1meta = loop1.get(); - Versioned l2meta = loop2.get(); - - Assert.assertEquals(l1meta, reference1.get()); - Assert.assertEquals(l2meta, reference2.get()); - - Assert.assertEquals(l1meta.getVersion().compare(l2meta.getVersion()), Version.Occurred.BEFORE); - - Assert.assertEquals(l1meta.getValue().getEnsembleAt(0L).get(0), b2); - Assert.assertEquals(l1meta.getValue().getEnsembleAt(0L).get(1), b1); - - Assert.assertEquals(l2meta.getValue().getEnsembleAt(0L).get(0), b2); - Assert.assertEquals(l2meta.getValue().getEnsembleAt(0L).get(1), b3); - - verify(lm, times(3)).writeLedgerMetadata(anyLong(), any(), any()); - } - } - - /** - * Test that when 2 updates loops try to make the same modification, and they - * conflict on the write to the store, the one that receives the conflict won't - * try to write again, as the value is now correct. - */ - @Test - public void testConflictOnWriteBothWritingSame() throws Exception { - try (BlockableMockLedgerManager lm = spy(new BlockableMockLedgerManager())) { - lm.blockWrites(); - - long ledgerId = 1234L; - BookieId b0 = BookieId.parse("0.0.0.0:3181"); - BookieId b1 = BookieId.parse("0.0.0.1:3181"); - BookieId b2 = BookieId.parse("0.0.0.2:3181"); - - LedgerMetadata initMeta = LedgerMetadataBuilder.create().withEnsembleSize(2).withId(ledgerId) - .withDigestType(DigestType.CRC32C).withPassword(new byte[0]) - .withWriteQuorumSize(2).newEnsembleEntry(0L, Lists.newArrayList(b0, b1)).build(); - Versioned writtenMetadata = lm.createLedgerMetadata(ledgerId, initMeta).get(); - AtomicReference> reference = new AtomicReference<>(writtenMetadata); - - CompletableFuture> loop1 = new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> currentMetadata.getEnsembleAt(0L).contains(b0), - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(0, b2); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference::compareAndSet).run(); - CompletableFuture> loop2 = new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> currentMetadata.getEnsembleAt(0L).contains(b0), - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(0, b2); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference::compareAndSet).run(); - - lm.releaseWrites(); - - Assert.assertEquals(loop1.get(), loop2.get()); - Assert.assertEquals(loop1.get(), reference.get()); - - Assert.assertEquals(reference.get().getValue().getEnsembleAt(0L).get(0), b2); - Assert.assertEquals(reference.get().getValue().getEnsembleAt(0L).get(1), b1); - - verify(lm, times(2)).writeLedgerMetadata(anyLong(), any(), any()); - } - } - - /** - * Test that when 2 update loops both manage to write, but conflict on - * updating the local value. - */ - @Test - public void testConflictOnLocalUpdate() throws Exception { - try (DeferCallbacksMockLedgerManager lm = spy(new DeferCallbacksMockLedgerManager(1))) { - long ledgerId = 1234L; - BookieId b0 = BookieId.parse("0.0.0.0:3181"); - BookieId b1 = BookieId.parse("0.0.0.1:3181"); - BookieId b2 = BookieId.parse("0.0.0.2:3181"); - BookieId b3 = BookieId.parse("0.0.0.3:3181"); - - LedgerMetadata initMeta = LedgerMetadataBuilder.create().withEnsembleSize(2).withId(ledgerId) - .withDigestType(DigestType.CRC32C).withPassword(new byte[0]) - .withWriteQuorumSize(2).newEnsembleEntry(0L, Lists.newArrayList(b0, b1)).build(); - Versioned writtenMetadata = lm.createLedgerMetadata(ledgerId, initMeta).get(); - AtomicReference> reference = new AtomicReference<>(writtenMetadata); - - CompletableFuture> loop1 = new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> currentMetadata.getEnsembleAt(0L).contains(b0), - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(0, b2); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference::compareAndSet).run(); - - lm.waitForWriteCount(1); - CompletableFuture> loop2 = new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> currentMetadata.getEnsembleAt(0L).contains(b1), - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(1, b3); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference::compareAndSet).run(); - Assert.assertEquals(loop2.get(), reference.get()); - - lm.runDeferred(); - - Assert.assertEquals(loop1.get(), reference.get()); - - Assert.assertEquals(reference.get().getValue().getEnsembleAt(0L).get(0), b2); - Assert.assertEquals(reference.get().getValue().getEnsembleAt(0L).get(1), b3); - - verify(lm, times(3)).writeLedgerMetadata(anyLong(), any(), any()); - } - } - - private static BookieId address(String s) { - try { - return BookieId.parse(s); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Hammer test. Kick off a lot of metadata updates concurrently with a ledger manager - * that runs callbacks on random threads, and validate all updates complete eventually, - * and that the final metadata reflects all the updates. - */ - @Test - public void testHammer() throws Exception { - try (NonDeterministicMockLedgerManager lm = new NonDeterministicMockLedgerManager()) { - long ledgerId = 1234L; - - int ensembleSize = 100; - List initialEnsemble = IntStream.range(0, ensembleSize) - .mapToObj((i) -> address(String.format("0.0.0.%d:3181", i))) - .collect(Collectors.toList()); - - LedgerMetadata initMeta = LedgerMetadataBuilder.create().withEnsembleSize(ensembleSize).withId(ledgerId) - .withDigestType(DigestType.CRC32C).withPassword(new byte[0]) - .newEnsembleEntry(0L, initialEnsemble).build(); - Versioned writtenMetadata = lm.createLedgerMetadata(ledgerId, initMeta).get(); - - AtomicReference> reference = new AtomicReference<>(writtenMetadata); - - List replacementBookies = IntStream.range(0, ensembleSize) - .mapToObj((i) -> address(String.format("0.0.%d.1:3181", i))) - .collect(Collectors.toList()); - - List>> loops = IntStream.range(0, ensembleSize) - .mapToObj((i) -> new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> currentMetadata.getEnsembleAt(0L).contains(initialEnsemble.get(i)), - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(i, replacementBookies.get(i)); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference::compareAndSet).run()) - .collect(Collectors.toList()); - - loops.forEach((l) -> l.join()); - - Assert.assertEquals(reference.get().getValue().getEnsembleAt(0L), replacementBookies); - } - } - - /** - * Test that if we have two conflicting updates, only one of the loops will complete. - * The other will throw an exception. - */ - @Test - public void testNewestValueCannotBeUsedAfterReadBack() throws Exception { - try (BlockableMockLedgerManager lm = spy(new BlockableMockLedgerManager())) { - lm.blockWrites(); - - long ledgerId = 1234L; - BookieId b0 = new BookieSocketAddress("0.0.0.0:3181").toBookieId(); - BookieId b1 = new BookieSocketAddress("0.0.0.1:3181").toBookieId(); - - LedgerMetadata initMeta = LedgerMetadataBuilder.create().withEnsembleSize(1).withId(ledgerId) - .withDigestType(DigestType.CRC32C).withPassword(new byte[0]) - .withWriteQuorumSize(1).withAckQuorumSize(1) - .newEnsembleEntry(0L, Lists.newArrayList(b0)).build(); - Versioned writtenMetadata = lm.createLedgerMetadata(ledgerId, initMeta).get(); - - AtomicReference> reference = new AtomicReference<>(writtenMetadata); - CompletableFuture> loop1 = new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> !currentMetadata.isClosed(), - (currentMetadata) -> { - return LedgerMetadataBuilder.from(currentMetadata) - .withClosedState().withLastEntryId(10L).withLength(100L).build(); - }, - reference::compareAndSet).run(); - CompletableFuture> loop2 = new MetadataUpdateLoop( - lm, - ledgerId, - reference::get, - (currentMetadata) -> { - if (currentMetadata.isClosed()) { - throw new BKException.BKLedgerClosedException(); - } else { - return currentMetadata.getEnsembleAt(0L).contains(b0); - } - }, - (currentMetadata) -> { - List ensemble = Lists.newArrayList(currentMetadata.getEnsembleAt(0L)); - ensemble.set(0, b1); - return LedgerMetadataBuilder.from(currentMetadata).replaceEnsembleEntry(0L, ensemble).build(); - }, - reference::compareAndSet).run(); - lm.releaseWrites(); - - Versioned l1meta = loop1.get(); - try { - loop2.get(); - Assert.fail("Update loop should have failed"); - } catch (ExecutionException ee) { - Assert.assertEquals(ee.getCause().getClass(), BKException.BKLedgerClosedException.class); - } - Assert.assertEquals(l1meta, reference.get()); - Assert.assertEquals(l1meta.getValue().getEnsembleAt(0L).get(0), b0); - Assert.assertTrue(l1meta.getValue().isClosed()); - - verify(lm, times(2)).writeLedgerMetadata(anyLong(), any(), any()); - } - } - - static class NonDeterministicMockLedgerManager extends MockLedgerManager { - final ExecutorService cbExecutor = Executors.newCachedThreadPool( - new ThreadFactoryBuilder().setNameFormat("non-deter-%d").build()); - - @Override - public void executeCallback(Runnable r) { - cbExecutor.execute(r); - } - - @Override - public void close() { - cbExecutor.shutdownNow(); - super.close(); - } - } - - static class DeferCallbacksMockLedgerManager extends MockLedgerManager { - int writeCount = 0; - final int numToDefer; - List>, Versioned, Throwable>> deferred = - Lists.newArrayList(); - - DeferCallbacksMockLedgerManager(int numToDefer) { - this.numToDefer = numToDefer; - } - - synchronized void runDeferred() { - deferred.forEach((d) -> { - Throwable t = d.getRight(); - if (t != null) { - d.getLeft().completeExceptionally(t); - } else { - d.getLeft().complete(d.getMiddle()); - } - }); - } - - synchronized void waitForWriteCount(int count) throws Exception { - while (writeCount < count) { - wait(); - } - } - - @Override - public synchronized CompletableFuture> writeLedgerMetadata( - long ledgerId, LedgerMetadata metadata, - Version currentVersion) { - CompletableFuture> promise = new CompletableFuture<>(); - super.writeLedgerMetadata(ledgerId, metadata, currentVersion) - .whenComplete((written, exception) -> { - synchronized (DeferCallbacksMockLedgerManager.this) { - if (writeCount++ < numToDefer) { - LOG.info("Added to deferals"); - deferred.add(Triple.of(promise, written, exception)); - } else { - LOG.info("Completing {}", numToDefer); - if (exception != null) { - promise.completeExceptionally(exception); - } else { - promise.complete(written); - } - } - DeferCallbacksMockLedgerManager.this.notifyAll(); - } - }); - return promise; - } - } - - @Data - @AllArgsConstructor - static class DeferredUpdate { - final CompletableFuture> promise; - final long ledgerId; - final LedgerMetadata metadata; - final Version currentVersion; - } - - static class BlockableMockLedgerManager extends MockLedgerManager { - boolean blocking = false; - List reqs = Lists.newArrayList(); - - synchronized void blockWrites() { - blocking = true; - } - - synchronized void releaseWrites() { - blocking = false; - reqs.forEach((r) -> { - super.writeLedgerMetadata(r.getLedgerId(), r.getMetadata(), - r.getCurrentVersion()) - .whenComplete((written, exception) -> { - if (exception != null) { - r.getPromise().completeExceptionally(exception); - } else { - r.getPromise().complete(written); - } - }); - }); - } - - @Override - public synchronized CompletableFuture> writeLedgerMetadata( - long ledgerId, LedgerMetadata metadata, Version currentVersion) { - if (blocking) { - CompletableFuture> promise = new CompletableFuture<>(); - reqs.add(new DeferredUpdate(promise, ledgerId, metadata, currentVersion)); - return promise; - } else { - return super.writeLedgerMetadata(ledgerId, metadata, currentVersion); - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeper.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeper.java deleted file mode 100644 index da1525ab8d1..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeper.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import io.netty.util.concurrent.DefaultThreadFactory; -import java.util.Arrays; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.client.AsyncCallback.CreateCallback; -import org.apache.bookkeeper.client.AsyncCallback.DeleteCallback; -import org.apache.bookkeeper.client.AsyncCallback.OpenCallback; -import org.apache.bookkeeper.client.api.BKException.Code; -import org.apache.bookkeeper.client.api.OpenBuilder; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.impl.OpenBuilderBase; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.zookeeper.ZooKeeper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Mocked version of BookKeeper client that keeps all ledgers data in memory. - * - *

This mocked client is meant to be used in unit tests for applications using the BookKeeper API. - */ -public class MockBookKeeper extends BookKeeper { - - final OrderedExecutor orderedExecutor = OrderedExecutor.newBuilder() - .numThreads(1) - .threadFactory(new DefaultThreadFactory("mock-bookkeeper")) - .build(); - final ZooKeeper zkc; - - @Override - public ClientConfiguration getConf() { - return super.getConf(); - } - - Map ledgers = new ConcurrentHashMap(); - AtomicLong sequence = new AtomicLong(3); - AtomicBoolean stopped = new AtomicBoolean(false); - AtomicInteger stepsToFail = new AtomicInteger(-1); - int failReturnCode = BKException.Code.OK; - int nextFailReturnCode = BKException.Code.OK; - - public MockBookKeeper(ZooKeeper zkc) throws Exception { - this.zkc = zkc; - } - - @Override - public OrderedExecutor getMainWorkerPool() { - return orderedExecutor; - } - - @Override - public LedgerHandle createLedger(DigestType digestType, byte[] passwd) throws BKException { - return createLedger(3, 2, digestType, passwd); - } - - @Override - public LedgerHandle createLedger(int ensSize, int qSize, DigestType digestType, byte[] passwd) throws BKException { - return createLedger(ensSize, qSize, qSize, digestType, passwd); - } - - @Override - public void asyncCreateLedger(int ensSize, int writeQuorumSize, int ackQuorumSize, final DigestType digestType, - final byte[] passwd, final CreateCallback cb, final Object ctx, Map properties) { - if (stopped.get()) { - cb.createComplete(BKException.Code.WriteException, null, ctx); - return; - } - - orderedExecutor.chooseThread().execute(new Runnable() { - public void run() { - if (getProgrammedFailStatus()) { - if (failReturnCode != BkTimeoutOperation) { - cb.createComplete(failReturnCode, null, ctx); - } - return; - } - - if (stopped.get()) { - cb.createComplete(BKException.Code.WriteException, null, ctx); - return; - } - - try { - long id = sequence.getAndIncrement(); - log.info("Creating ledger {}", id); - MockLedgerHandle lh = new MockLedgerHandle(MockBookKeeper.this, id, digestType, passwd); - ledgers.put(id, lh); - lh.executeOrdered(() -> cb.createComplete(0, lh, ctx)); - } catch (Throwable t) { - log.error("Error", t); - } - } - }); - } - - @Override - public LedgerHandle createLedger(int ensSize, int writeQuorumSize, int ackQuorumSize, DigestType digestType, - byte[] passwd) throws BKException { - checkProgrammedFail(); - - if (stopped.get()) { - throw BKException.create(BKException.Code.WriteException); - } - - try { - long id = sequence.getAndIncrement(); - log.info("Creating ledger {}", id); - MockLedgerHandle lh = new MockLedgerHandle(this, id, digestType, passwd); - ledgers.put(id, lh); - return lh; - } catch (Throwable t) { - log.error("Exception:", t); - return null; - } - } - - @Override - public void asyncCreateLedger(int ensSize, int qSize, DigestType digestType, byte[] passwd, CreateCallback cb, - Object ctx) { - asyncCreateLedger(ensSize, qSize, qSize, digestType, passwd, cb, ctx, Collections.emptyMap()); - } - - @Override - public void asyncOpenLedger(long lId, DigestType digestType, byte[] passwd, OpenCallback cb, Object ctx) { - if (getProgrammedFailStatus()) { - if (failReturnCode != BkTimeoutOperation) { - cb.openComplete(failReturnCode, null, ctx); - } - return; - } - - if (stopped.get()) { - cb.openComplete(BKException.Code.WriteException, null, ctx); - return; - } - - MockLedgerHandle lh = ledgers.get(lId); - if (lh == null) { - cb.openComplete(BKException.Code.NoSuchLedgerExistsOnMetadataServerException, null, ctx); - } else if (lh.digest != digestType) { - cb.openComplete(BKException.Code.DigestMatchException, null, ctx); - } else if (!Arrays.equals(lh.passwd, passwd)) { - cb.openComplete(BKException.Code.UnauthorizedAccessException, null, ctx); - } else { - lh.executeOrdered(() -> cb.openComplete(0, lh, ctx)); - } - } - - @Override - public void asyncOpenLedgerNoRecovery(long lId, DigestType digestType, byte[] passwd, OpenCallback cb, Object ctx) { - asyncOpenLedger(lId, digestType, passwd, cb, ctx); - } - - @Override - public void asyncDeleteLedger(long lId, DeleteCallback cb, Object ctx) { - if (getProgrammedFailStatus()) { - if (failReturnCode != BkTimeoutOperation) { - cb.deleteComplete(failReturnCode, ctx); - } - } else if (stopped.get()) { - cb.deleteComplete(BKException.Code.WriteException, ctx); - } else if (ledgers.containsKey(lId)) { - ledgers.remove(lId); - cb.deleteComplete(0, ctx); - } else { - cb.deleteComplete(BKException.Code.NoSuchLedgerExistsOnMetadataServerException, ctx); - } - } - - @Override - public void deleteLedger(long lId) throws InterruptedException, BKException { - checkProgrammedFail(); - - if (stopped.get()) { - throw BKException.create(BKException.Code.WriteException); - } - - if (!ledgers.containsKey(lId)) { - throw BKException.create(BKException.Code.NoSuchLedgerExistsOnMetadataServerException); - } - - ledgers.remove(lId); - } - - @Override - public void close() throws InterruptedException, BKException { - checkProgrammedFail(); - shutdown(); - } - - @Override - public OpenBuilder newOpenLedgerOp() { - return new OpenBuilderBase() { - @Override - public CompletableFuture execute() { - CompletableFuture promise = new CompletableFuture(); - - final int validateRc = validate(); - if (Code.OK != validateRc) { - promise.completeExceptionally(BKException.create(validateRc)); - return promise; - } else if (getProgrammedFailStatus()) { - if (failReturnCode != BkTimeoutOperation) { - promise.completeExceptionally(BKException.create(failReturnCode)); - } - return promise; - } else if (stopped.get()) { - promise.completeExceptionally(new BKException.BKClientClosedException()); - return promise; - } - - MockLedgerHandle lh = ledgers.get(ledgerId); - if (lh == null) { - promise.completeExceptionally(new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } else if (lh.digest != DigestType.fromApiDigestType(digestType)) { - promise.completeExceptionally(new BKException.BKDigestMatchException()); - } else if (!Arrays.equals(lh.passwd, password)) { - promise.completeExceptionally(new BKException.BKUnauthorizedAccessException()); - } else { - promise.complete(new MockReadHandle(MockBookKeeper.this, ledgerId, - lh.getLedgerMetadata(), lh.entries)); - } - return promise; - } - }; - } - - public void shutdown() { - try { - super.close(); - } catch (Exception e) { - } - stopped.set(true); - for (MockLedgerHandle ledger : ledgers.values()) { - ledger.entries.clear(); - } - - ledgers.clear(); - orderedExecutor.shutdownNow(); - } - - public boolean isStopped() { - return stopped.get(); - } - - public Set getLedgers() { - return ledgers.keySet(); - } - - void checkProgrammedFail() throws BKException { - int steps = stepsToFail.getAndDecrement(); - if (log.isDebugEnabled()) { - log.debug("Steps to fail: {}", steps); - } - if (steps <= 0) { - if (failReturnCode != BKException.Code.OK) { - int rc = failReturnCode; - failReturnCode = nextFailReturnCode; - nextFailReturnCode = BKException.Code.OK; - throw BKException.create(rc); - } - } - } - - boolean getProgrammedFailStatus() { - int steps = stepsToFail.getAndDecrement(); - if (log.isDebugEnabled()) { - log.debug("Steps to fail: {}", steps); - } - return steps == 0; - } - - public void failNow(int rc) { - failNow(rc, BKException.Code.OK); - } - - public void failNow(int rc, int nextErrorCode) { - failAfter(0, rc); - } - - public void failAfter(int steps, int rc) { - failAfter(steps, rc, BKException.Code.OK); - } - - public void failAfter(int steps, int rc, int nextErrorCode) { - stepsToFail.set(steps); - failReturnCode = rc; - this.nextFailReturnCode = nextErrorCode; - } - - public void timeoutAfter(int steps) { - stepsToFail.set(steps); - failReturnCode = BkTimeoutOperation; - } - - private static final int BkTimeoutOperation = 1000; - - private static final Logger log = LoggerFactory.getLogger(MockBookKeeper.class); -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTest.java deleted file mode 100644 index a7405934715..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.Enumeration; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.junit.Test; - -/** - * Test the mocked BookKeeper client. - */ -public class MockBookKeeperTest { - - @Test - public void testMockedBookKeeper() throws Exception { - BookKeeper bkc = new MockBookKeeper(null); - - LedgerHandle lh = bkc.createLedger(DigestType.CRC32, new byte[0]); - - assertEquals(0, lh.addEntry("entry-0".getBytes())); - assertEquals(1, lh.addEntry("entry-1".getBytes())); - - assertEquals(1, lh.getLastAddConfirmed()); - - Enumeration entries = lh.readEntries(0, 1); - assertTrue(entries.hasMoreElements()); - assertEquals("entry-0", new String(entries.nextElement().getEntry())); - assertTrue(entries.hasMoreElements()); - assertEquals("entry-1", new String(entries.nextElement().getEntry())); - assertFalse(entries.hasMoreElements()); - - lh.close(); - bkc.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTestCase.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTestCase.java deleted file mode 100644 index e1881d74771..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTestCase.java +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static com.google.common.base.Preconditions.checkState; -import static org.apache.bookkeeper.client.api.BKException.Code.NoBookieAvailableException; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyMap; -import static org.mockito.ArgumentMatchers.anySet; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.util.ReferenceCounted; -import java.security.GeneralSecurityException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.apache.bookkeeper.client.BKException.BKDigestMatchException; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.api.CreateBuilder; -import org.apache.bookkeeper.client.api.DeleteBuilder; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.OpenBuilder; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.LedgerIdGenerator; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieAddressResolver; -import org.apache.bookkeeper.proto.BookieClient; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.ByteBufList; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.After; -import org.junit.Before; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.mockito.stubbing.Stubber; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Base class for Mock-based Client testcases. - */ -public abstract class MockBookKeeperTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(MockBookKeeperTestCase.class); - - protected OrderedScheduler scheduler; - protected OrderedExecutor executor; - protected BookKeeper bk; - protected BookieClient bookieClient; - protected LedgerManager ledgerManager; - protected LedgerIdGenerator ledgerIdGenerator; - protected EnsemblePlacementPolicy placementPolicy; - - private BookieWatcher bookieWatcher; - - protected ConcurrentMap mockLedgerMetadataRegistry; - protected AtomicLong mockNextLedgerId; - protected ConcurrentSkipListSet fencedLedgers; - protected ConcurrentMap>> mockLedgerData; - - private Map> deferredBookieForceLedgerResponses; - private Set suspendedBookiesForForceLedgerAcks; - - List failedBookies; - Set availableBookies; - private int lastIndexForBK; - protected int maxNumberOfAvailableBookies = Integer.MAX_VALUE; - - private Map> getMockLedgerContents(long ledgerId) { - return mockLedgerData.computeIfAbsent(ledgerId, (id) -> new ConcurrentHashMap<>()); - } - - private Map getMockLedgerContentsInBookie(long ledgerId, BookieId bookieSocketAddress) { - return getMockLedgerContents(ledgerId).computeIfAbsent(bookieSocketAddress, addr -> new ConcurrentHashMap<>()); - } - - private MockEntry getMockLedgerEntry(long ledgerId, - BookieId bookieSocketAddress, long entryId) throws BKException{ - if (failedBookies.contains(bookieSocketAddress)) { - throw BKException.create(NoBookieAvailableException); - } - return getMockLedgerContentsInBookie(ledgerId, bookieSocketAddress).get(entryId); - } - - private static final class MockEntry { - - byte[] payload; - long lastAddConfirmed; - - public MockEntry(byte[] payload, long lastAddConfirmed) { - this.payload = payload; - this.lastAddConfirmed = lastAddConfirmed; - } - - } - - @Before - public void setup() throws Exception { - maxNumberOfAvailableBookies = Integer.MAX_VALUE; - deferredBookieForceLedgerResponses = new ConcurrentHashMap<>(); - suspendedBookiesForForceLedgerAcks = Collections.synchronizedSet(new HashSet<>()); - mockLedgerMetadataRegistry = new ConcurrentHashMap<>(); - mockLedgerData = new ConcurrentHashMap<>(); - mockNextLedgerId = new AtomicLong(1); - fencedLedgers = new ConcurrentSkipListSet<>(); - scheduler = OrderedScheduler.newSchedulerBuilder().numThreads(4).name("bk-test").build(); - executor = OrderedExecutor.newBuilder().build(); - bookieWatcher = mock(BookieWatcher.class); - placementPolicy = new DefaultEnsemblePlacementPolicy(); - - bookieClient = mock(BookieClient.class); - ledgerManager = mock(LedgerManager.class); - ledgerIdGenerator = mock(LedgerIdGenerator.class); - BookieAddressResolver bookieAddressResolver = BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER; - when(bookieWatcher.getBookieAddressResolver()).thenReturn(bookieAddressResolver); - - bk = mock(BookKeeper.class); - doReturn(new ClientConfiguration()).when(bk).getConf(); - - failedBookies = new ArrayList<>(); - availableBookies = new HashSet<>(); - - when(bk.getCloseLock()).thenReturn(new ReentrantReadWriteLock()); - when(bk.isClosed()).thenReturn(false); - when(bk.getBookieWatcher()).thenReturn(bookieWatcher); - when(bk.getBookieAddressResolver()).thenReturn(bookieAddressResolver); - when(bk.getMainWorkerPool()).thenReturn(executor); - when(bk.getBookieClient()).thenReturn(bookieClient); - when(bk.getScheduler()).thenReturn(scheduler); - - setBookKeeperConfig(new ClientConfiguration()); - when(bk.getStatsLogger()).thenReturn(NullStatsLogger.INSTANCE); - BookKeeperClientStats clientStats = BookKeeperClientStats.newInstance(NullStatsLogger.INSTANCE); - ClientContext clientCtx = new ClientContext() { - @Override - public ClientInternalConf getConf() { - return ClientInternalConf.fromConfig(bk.getConf()); - } - - @Override - public LedgerManager getLedgerManager() { - return ledgerManager; - } - - @Override - public BookieWatcher getBookieWatcher() { - return bookieWatcher; - } - - @Override - public EnsemblePlacementPolicy getPlacementPolicy() { - return placementPolicy; - } - - @Override - public BookieClient getBookieClient() { - return bookieClient; - } - - @Override - public OrderedExecutor getMainWorkerPool() { - return scheduler; - } - - @Override - public OrderedScheduler getScheduler() { - return scheduler; - } - - @Override - public BookKeeperClientStats getClientStats() { - return clientStats; - } - - @Override - public boolean isClientClosed() { - return bk.isClosed(); - } - - @Override - public ByteBufAllocator getByteBufAllocator() { - return UnpooledByteBufAllocator.DEFAULT; - } - }; - when(bk.getClientCtx()).thenReturn(clientCtx); - when(bk.getLedgerManager()).thenReturn(ledgerManager); - when(bk.getLedgerIdGenerator()).thenReturn(ledgerIdGenerator); - when(bk.getReturnRc(anyInt())).thenAnswer(invocationOnMock -> invocationOnMock.getArgument(0)); - when(bookieClient.isWritable(any(), anyLong())).thenReturn(true); - - setupLedgerIdGenerator(); - setupCreateLedgerMetadata(); - setupReadLedgerMetadata(); - setupWriteLedgerMetadata(); - setupRemoveLedgerMetadata(); - setupRegisterLedgerMetadataListener(); - setupBookieWatcherForNewEnsemble(); - setupBookieWatcherForEnsembleChange(); - setupBookieClientReadEntry(); - setupBookieClientReadLac(); - setupBookieClientAddEntry(); - setupBookieClientForceLedger(); - } - - protected void setBookKeeperConfig(ClientConfiguration conf) { - when(bk.getConf()).thenReturn(conf); - } - - private DigestManager getDigestType(long ledgerId) throws GeneralSecurityException { - LedgerMetadata metadata = mockLedgerMetadataRegistry.get(ledgerId); - return DigestManager.instantiate( - ledgerId, - metadata.getPassword(), - org.apache.bookkeeper.client.BookKeeper.DigestType.toProtoDigestType( - org.apache.bookkeeper.client.BookKeeper.DigestType.fromApiDigestType( - metadata.getDigestType())), - UnpooledByteBufAllocator.DEFAULT, false); - } - - @After - public void tearDown() { - scheduler.shutdown(); - executor.shutdown(); - } - - protected CreateBuilder newCreateLedgerOp() { - return new LedgerCreateOp.CreateBuilderImpl(bk); - } - - protected OpenBuilder newOpenLedgerOp() { - return new LedgerOpenOp.OpenBuilderImpl(bk); - } - - protected DeleteBuilder newDeleteLedgerOp() { - return new LedgerDeleteOp.DeleteBuilderImpl(bk); - } - - protected void closeBookkeeper() { - when(bk.isClosed()).thenReturn(true); - } - - protected void killBookie(BookieId killedBookieSocketAddress) { - failedBookies.add(killedBookieSocketAddress); - availableBookies.remove(killedBookieSocketAddress); - } - - protected void startKilledBookie(BookieId killedBookieSocketAddress) { - checkState(failedBookies.contains(killedBookieSocketAddress)); - checkState(!availableBookies.contains(killedBookieSocketAddress)); - failedBookies.remove(killedBookieSocketAddress); - availableBookies.add(killedBookieSocketAddress); - } - - protected void suspendBookieForceLedgerAcks(BookieId address) { - suspendedBookiesForForceLedgerAcks.add(address); - } - - protected void resumeBookieWriteAcks(BookieId address) { - List pendingResponses; - - // why use the BookieId instance as the object monitor? there is a date race problem if not - // see https://github.com/apache/bookkeeper/issues/4200 - synchronized (address) { - suspendedBookiesForForceLedgerAcks.remove(address); - pendingResponses = deferredBookieForceLedgerResponses.remove(address); - } - - if (pendingResponses != null) { - pendingResponses.forEach(Runnable::run); - } - } - - protected BookieId startNewBookie() { - BookieId address = generateBookieSocketAddress(lastIndexForBK++); - availableBookies.add(address); - return address; - } - - protected BookieId generateBookieSocketAddress(int index) { - return new BookieSocketAddress("localhost", 1111 + index).toBookieId(); - } - - protected ArrayList generateNewEnsemble(int ensembleSize) throws BKException.BKNotEnoughBookiesException { - LOG.info("generateNewEnsemble {}", ensembleSize); - if (ensembleSize > maxNumberOfAvailableBookies) { - throw new BKException.BKNotEnoughBookiesException(); - } - ArrayList ensemble = new ArrayList<>(ensembleSize); - for (int i = 0; i < ensembleSize; i++) { - ensemble.add(generateBookieSocketAddress(i)); - } - availableBookies.addAll(ensemble); - lastIndexForBK = ensembleSize; - return ensemble; - } - - private void setupBookieWatcherForNewEnsemble() throws BKException.BKNotEnoughBookiesException { - when(bookieWatcher.newEnsemble(anyInt(), anyInt(), anyInt(), any())) - .thenAnswer((Answer>) new Answer>() { - @Override - @SuppressWarnings("unchecked") - public ArrayList answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - int ensembleSize = (Integer) args[0]; - return generateNewEnsemble(ensembleSize); - } - }); - } - - private void setupBookieWatcherForEnsembleChange() throws BKException.BKNotEnoughBookiesException { - when(bookieWatcher.replaceBookie(anyInt(), anyInt(), anyInt(), anyMap(), anyList(), anyInt(), anySet())) - .thenAnswer((Answer) new Answer() { - @Override - @SuppressWarnings("unchecked") - public BookieId answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - List existingBookies = (List) args[4]; - Set excludeBookies = (Set) args[6]; - excludeBookies.addAll(existingBookies); - Set remainBookies = new HashSet(availableBookies); - remainBookies.removeAll(excludeBookies); - if (remainBookies.iterator().hasNext()) { - return remainBookies.iterator().next(); - } - throw BKException.create(BKException.Code.NotEnoughBookiesException); - } - }); - } - - protected void registerMockEntryForRead(long ledgerId, long entryId, BookieId bookieSocketAddress, - byte[] entryData, long lastAddConfirmed) { - getMockLedgerContentsInBookie(ledgerId, bookieSocketAddress).put(entryId, new MockEntry(entryData, - lastAddConfirmed)); - } - - protected void registerMockLedgerMetadata(long ledgerId, LedgerMetadata ledgerMetadata) { - mockLedgerMetadataRegistry.put(ledgerId, ledgerMetadata); - } - - protected void setNewGeneratedLedgerId(long ledgerId) { - mockNextLedgerId.set(ledgerId); - setupLedgerIdGenerator(); - } - - protected LedgerMetadata getLedgerMetadata(long ledgerId) { - return mockLedgerMetadataRegistry.get(ledgerId); - } - - @SuppressWarnings("unchecked") - private void setupReadLedgerMetadata() { - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - Long ledgerId = (Long) args[0]; - CompletableFuture> promise = new CompletableFuture<>(); - executor.executeOrdered(ledgerId, () -> { - LedgerMetadata ledgerMetadata = mockLedgerMetadataRegistry.get(ledgerId); - if (ledgerMetadata == null) { - promise.completeExceptionally(new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } else { - promise.complete(new Versioned<>(ledgerMetadata, new LongVersion(1))); - } - }); - return promise; - }).when(ledgerManager).readLedgerMetadata(anyLong()); - } - - @SuppressWarnings("unchecked") - private void setupRemoveLedgerMetadata() { - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - Long ledgerId = (Long) args[0]; - CompletableFuture promise = new CompletableFuture<>(); - executor.executeOrdered(ledgerId, () -> { - if (mockLedgerMetadataRegistry.remove(ledgerId) != null) { - promise.complete(null); - } else { - promise.completeExceptionally(new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } - }); - return promise; - }).when(ledgerManager).removeLedgerMetadata(anyLong(), any()); - } - - private void setupRegisterLedgerMetadataListener() { - doAnswer((Answer) new Answer() { - @Override - @SuppressWarnings("unchecked") - public Void answer(InvocationOnMock invocation) throws Throwable { - return null; - } - }).when(ledgerManager).registerLedgerMetadataListener(anyLong(), any()); - } - - @SuppressWarnings("unchecked") - private void setupLedgerIdGenerator() { - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - BookkeeperInternalCallbacks.GenericCallback cb = (BookkeeperInternalCallbacks.GenericCallback) args[0]; - cb.operationComplete(Code.OK, mockNextLedgerId.getAndIncrement()); - return null; - }).when(ledgerIdGenerator).generateLedgerId(any()); - } - - @SuppressWarnings("unchecked") - private void setupCreateLedgerMetadata() { - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - Long ledgerId = (Long) args[0]; - - CompletableFuture> promise = new CompletableFuture<>(); - executor.executeOrdered(ledgerId, () -> { - - LedgerMetadata ledgerMetadata = (LedgerMetadata) args[1]; - mockLedgerMetadataRegistry.put(ledgerId, ledgerMetadata); - promise.complete(new Versioned<>(ledgerMetadata, new LongVersion(1))); - }); - return promise; - }).when(ledgerManager).createLedgerMetadata(anyLong(), any()); - } - - @SuppressWarnings("unchecked") - private void setupWriteLedgerMetadata() { - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - Long ledgerId = (Long) args[0]; - LedgerMetadata metadata = (LedgerMetadata) args[1]; - Version currentVersion = (Version) args[2]; - CompletableFuture> promise = new CompletableFuture<>(); - executor.executeOrdered(ledgerId, () -> { - LedgerMetadata newMetadata = LedgerMetadataBuilder.from(metadata).build(); - mockLedgerMetadataRegistry.put(ledgerId, newMetadata); - promise.complete(new Versioned<>(newMetadata, new LongVersion(1234))); - }); - return promise; - }).when(ledgerManager).writeLedgerMetadata(anyLong(), any(), any()); - } - - @SuppressWarnings("unchecked") - protected void setupBookieClientReadEntry() { - final Stubber stub = doAnswer(invokation -> { - Object[] args = invokation.getArguments(); - BookieId bookieSocketAddress = (BookieId) args[0]; - long ledgerId = (Long) args[1]; - long entryId = (Long) args[2]; - BookkeeperInternalCallbacks.ReadEntryCallback callback = - (BookkeeperInternalCallbacks.ReadEntryCallback) args[3]; - boolean fenced = (((Integer) args[5]) & BookieProtocol.FLAG_DO_FENCING) == BookieProtocol.FLAG_DO_FENCING; - - executor.executeOrdered(ledgerId, () -> { - DigestManager macManager = null; - try { - macManager = getDigestType(ledgerId); - } catch (GeneralSecurityException gse){ - LOG.error("Initialize macManager fail", gse); - } - MockEntry mockEntry = null; - try { - mockEntry = getMockLedgerEntry(ledgerId, bookieSocketAddress, entryId); - } catch (BKException bke) { - LOG.info("readEntryAndFenceLedger - occur BKException {}@{} at {}", entryId, ledgerId, - bookieSocketAddress); - callback.readEntryComplete(bke.getCode(), ledgerId, entryId, null, args[5]); - } - - if (fenced) { - fencedLedgers.add(ledgerId); - } - - if (mockEntry != null) { - LOG.info("readEntry - found mock entry {}@{} at {}", entryId, ledgerId, bookieSocketAddress); - ReferenceCounted entry = macManager.computeDigestAndPackageForSending(entryId, - mockEntry.lastAddConfirmed, mockEntry.payload.length, - Unpooled.wrappedBuffer(mockEntry.payload), new byte[20], 0); - callback.readEntryComplete(BKException.Code.OK, ledgerId, entryId, MockBookieClient.copyData(entry), - args[4]); - entry.release(); - } else { - LOG.info("readEntry - no such mock entry {}@{} at {}", entryId, ledgerId, bookieSocketAddress); - callback.readEntryComplete(BKException.Code.NoSuchEntryException, ledgerId, entryId, null, args[4]); - } - }); - return null; - }); - - stub.when(bookieClient).readEntry(any(), anyLong(), anyLong(), - any(BookkeeperInternalCallbacks.ReadEntryCallback.class), - any(), anyInt()); - - stub.when(bookieClient).readEntry(any(), anyLong(), anyLong(), - any(BookkeeperInternalCallbacks.ReadEntryCallback.class), - any(), anyInt(), any()); - - stub.when(bookieClient).readEntry(any(), anyLong(), anyLong(), - any(BookkeeperInternalCallbacks.ReadEntryCallback.class), - any(), anyInt(), any(), anyBoolean()); - } - - @SuppressWarnings("unchecked") - protected void setupBookieClientReadLac() { - final Stubber stub = doAnswer(invokation -> { - Object[] args = invokation.getArguments(); - BookieId bookieSocketAddress = (BookieId) args[0]; - long ledgerId = (Long) args[1]; - final BookkeeperInternalCallbacks.ReadLacCallback callback = - (BookkeeperInternalCallbacks.ReadLacCallback) args[2]; - Object ctx = args[3]; - long entryId = BookieProtocol.LAST_ADD_CONFIRMED; - // simply use "readEntry" with LAST_ADD_CONFIRMED to get current LAC - // there is nothing that writes ExplicitLAC within MockBookKeeperTestCase - bookieClient.readEntry(bookieSocketAddress, ledgerId, entryId, - new BookkeeperInternalCallbacks.ReadEntryCallback() { - @Override - public void readEntryComplete(int rc, long ledgerId, long entryId, ByteBuf buffer, Object ctx) { - callback.readLacComplete(rc, ledgerId, null, buffer, ctx); - } - }, ctx, BookieProtocol.FLAG_NONE); - return null; - }); - - stub.when(bookieClient).readLac(any(BookieId.class), anyLong(), - any(BookkeeperInternalCallbacks.ReadLacCallback.class), - any()); - } - - private byte[] extractEntryPayload(long ledgerId, long entryId, ByteBufList toSend) - throws BKException.BKDigestMatchException { - ByteBuf toSendCopy = Unpooled.copiedBuffer(toSend.toArray()); - toSendCopy.resetReaderIndex(); - DigestManager macManager = null; - try { - macManager = getDigestType(ledgerId); - } catch (GeneralSecurityException gse){ - LOG.error("Initialize macManager fail", gse); - } - ByteBuf content = macManager.verifyDigestAndReturnData(entryId, toSendCopy); - byte[] entry = new byte[content.readableBytes()]; - content.readBytes(entry); - content.resetReaderIndex(); - content.release(); - return entry; - } - - @SuppressWarnings("unchecked") - protected void setupBookieClientAddEntry() { - final Stubber stub = doAnswer(invokation -> { - Object[] args = invokation.getArguments(); - BookkeeperInternalCallbacks.WriteCallback callback = (BookkeeperInternalCallbacks.WriteCallback) args[5]; - BookieId bookieSocketAddress = (BookieId) args[0]; - long ledgerId = (Long) args[1]; - long entryId = (Long) args[3]; - ByteBufList toSend = (ByteBufList) args[4]; - Object ctx = args[6]; - int options = (int) args[7]; - boolean isRecoveryAdd = - ((short) options & BookieProtocol.FLAG_RECOVERY_ADD) == BookieProtocol.FLAG_RECOVERY_ADD; - - toSend.retain(); - executor.executeOrdered(ledgerId, () -> { - byte[] entry; - try { - entry = extractEntryPayload(ledgerId, entryId, toSend); - } catch (BKDigestMatchException e) { - callback.writeComplete(Code.DigestMatchException, - ledgerId, entryId, bookieSocketAddress, ctx); - toSend.release(); - return; - } - boolean fenced = fencedLedgers.contains(ledgerId); - if (fenced && !isRecoveryAdd) { - callback.writeComplete(BKException.Code.LedgerFencedException, - ledgerId, entryId, bookieSocketAddress, ctx); - } else { - if (failedBookies.contains(bookieSocketAddress)) { - callback.writeComplete(NoBookieAvailableException, - ledgerId, entryId, bookieSocketAddress, ctx); - toSend.release(); - return; - } - if (getMockLedgerContentsInBookie(ledgerId, bookieSocketAddress).isEmpty()) { - registerMockEntryForRead(ledgerId, BookieProtocol.LAST_ADD_CONFIRMED, - bookieSocketAddress, new byte[0], BookieProtocol.INVALID_ENTRY_ID); - } - registerMockEntryForRead(ledgerId, entryId, bookieSocketAddress, entry, ledgerId); - callback.writeComplete(BKException.Code.OK, - ledgerId, entryId, bookieSocketAddress, ctx); - } - toSend.release(); - }); - - return null; - }); - - stub.when(bookieClient).addEntry(any(BookieId.class), - anyLong(), any(byte[].class), - anyLong(), any(ByteBufList.class), - any(BookkeeperInternalCallbacks.WriteCallback.class), - any(), anyInt(), anyBoolean(), any(EnumSet.class)); - } - - @SuppressWarnings("unchecked") - protected void setupBookieClientForceLedger() { - final Stubber stub = doAnswer(invokation -> { - Object[] args = invokation.getArguments(); - BookieId bookieSocketAddress = (BookieId) args[0]; - long ledgerId = (Long) args[1]; - BookkeeperInternalCallbacks.ForceLedgerCallback callback = - (BookkeeperInternalCallbacks.ForceLedgerCallback) args[2]; - Object ctx = args[3]; - - Runnable activity = () -> { - executor.executeOrdered(ledgerId, () -> { - if (failedBookies.contains(bookieSocketAddress)) { - callback.forceLedgerComplete(NoBookieAvailableException, ledgerId, bookieSocketAddress, ctx); - return; - } - callback.forceLedgerComplete(BKException.Code.OK, ledgerId, bookieSocketAddress, ctx); - }); - }; - List queue = null; - - synchronized (bookieSocketAddress) { - if (suspendedBookiesForForceLedgerAcks.contains(bookieSocketAddress)) { - queue = deferredBookieForceLedgerResponses.computeIfAbsent(bookieSocketAddress, - (k) -> new CopyOnWriteArrayList<>()); - queue.add(activity); - } - } - - if (queue == null) { - activity.run(); - } - return null; - }); - - stub.when(bookieClient).forceLedger(any(BookieId.class), - anyLong(), - any(BookkeeperInternalCallbacks.ForceLedgerCallback.class), - any()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockClientContext.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockClientContext.java deleted file mode 100644 index 93078a05129..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockClientContext.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static com.google.common.base.Preconditions.checkState; - -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.util.function.BooleanSupplier; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.discover.MockRegistrationClient; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.MockLedgerManager; -import org.apache.bookkeeper.proto.BookieClient; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.apache.bookkeeper.proto.MockBookies; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.mockito.Mockito; - -/** - * Mock client context to allow testing client functionality with no external dependencies. - * The client context can be created with defaults, copied from another context or constructed from scratch. - */ -public class MockClientContext implements ClientContext { - private ClientInternalConf internalConf; - private LedgerManager ledgerManager; - private BookieWatcher bookieWatcher; - private EnsemblePlacementPolicy placementPolicy; - private BookieClient bookieClient; - private OrderedExecutor mainWorkerPool; - private OrderedScheduler scheduler; - private BookKeeperClientStats clientStats; - private BooleanSupplier isClientClosed; - private MockRegistrationClient regClient; - private ByteBufAllocator allocator; - - static MockClientContext create(MockBookies mockBookies) throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder().name("mock-executor").numThreads(1).build(); - MockRegistrationClient regClient = new MockRegistrationClient(); - EnsemblePlacementPolicy placementPolicy = new DefaultEnsemblePlacementPolicy(); - BookieWatcherImpl bookieWatcherImpl = new BookieWatcherImpl(conf, placementPolicy, - regClient, - new DefaultBookieAddressResolver(regClient), - NullStatsLogger.INSTANCE); - bookieWatcherImpl.initialBlockingBookieRead(); - - return new MockClientContext() - .setConf(ClientInternalConf.fromConfig(conf)) - .setLedgerManager(new MockLedgerManager()) - .setBookieWatcher(bookieWatcherImpl) - .setPlacementPolicy(placementPolicy) - .setRegistrationClient(regClient) - .setBookieClient(new MockBookieClient(scheduler, mockBookies)) - .setByteBufAllocator(UnpooledByteBufAllocator.DEFAULT) - .setMainWorkerPool(scheduler) - .setScheduler(scheduler) - .setClientStats(BookKeeperClientStats.newInstance(NullStatsLogger.INSTANCE)) - .setIsClientClosed(() -> false); - } - - static MockClientContext create() throws Exception { - MockBookies mockBookies = new MockBookies(); - return create(mockBookies); - } - - static MockClientContext copyOf(ClientContext other) { - return new MockClientContext() - .setConf(other.getConf()) - .setLedgerManager(other.getLedgerManager()) - .setBookieWatcher(other.getBookieWatcher()) - .setPlacementPolicy(other.getPlacementPolicy()) - .setBookieClient(other.getBookieClient()) - .setMainWorkerPool(other.getMainWorkerPool()) - .setScheduler(other.getScheduler()) - .setClientStats(other.getClientStats()) - .setByteBufAllocator(other.getByteBufAllocator()) - .setIsClientClosed(other::isClientClosed); - } - - public MockRegistrationClient getMockRegistrationClient() { - checkState(regClient != null); - return regClient; - } - - public MockLedgerManager getMockLedgerManager() { - checkState(ledgerManager instanceof MockLedgerManager); - return (MockLedgerManager) ledgerManager; - } - - public MockBookieClient getMockBookieClient() { - checkState(bookieClient instanceof MockBookieClient); - return (MockBookieClient) bookieClient; - } - - public MockClientContext setConf(ClientInternalConf internalConf) { - this.internalConf = maybeSpy(internalConf); - return this; - } - - public MockClientContext setLedgerManager(LedgerManager ledgerManager) { - this.ledgerManager = maybeSpy(ledgerManager); - return this; - } - - public MockClientContext setBookieWatcher(BookieWatcher bookieWatcher) { - this.bookieWatcher = maybeSpy(bookieWatcher); - return this; - } - - public MockClientContext setPlacementPolicy(EnsemblePlacementPolicy placementPolicy) { - this.placementPolicy = maybeSpy(placementPolicy); - return this; - } - - public MockClientContext setBookieClient(BookieClient bookieClient) { - this.bookieClient = maybeSpy(bookieClient); - return this; - } - - public MockClientContext setMainWorkerPool(OrderedExecutor mainWorkerPool) { - this.mainWorkerPool = maybeSpy(mainWorkerPool); - return this; - } - - public MockClientContext setScheduler(OrderedScheduler scheduler) { - this.scheduler = maybeSpy(scheduler); - return this; - } - - public MockClientContext setClientStats(BookKeeperClientStats clientStats) { - this.clientStats = clientStats; - return this; - } - - public MockClientContext setIsClientClosed(BooleanSupplier isClientClosed) { - this.isClientClosed = isClientClosed; - return this; - } - - public MockClientContext setRegistrationClient(MockRegistrationClient regClient) { - this.regClient = maybeSpy(regClient); - return this; - } - - public MockClientContext setByteBufAllocator(ByteBufAllocator allocator) { - this.allocator = allocator; - return this; - } - - private static T maybeSpy(T orig) { - if (Mockito.mockingDetails(orig).isSpy()) { - return orig; - } else { - return Mockito.spy(orig); - } - } - - @Override - public ClientInternalConf getConf() { - return this.internalConf; - } - - @Override - public LedgerManager getLedgerManager() { - return this.ledgerManager; - } - - @Override - public BookieWatcher getBookieWatcher() { - return this.bookieWatcher; - } - - @Override - public EnsemblePlacementPolicy getPlacementPolicy() { - return this.placementPolicy; - } - - @Override - public BookieClient getBookieClient() { - return this.bookieClient; - } - - @Override - public OrderedExecutor getMainWorkerPool() { - return this.mainWorkerPool; - } - - @Override - public OrderedScheduler getScheduler() { - return this.scheduler; - } - - @Override - public BookKeeperClientStats getClientStats() { - return clientStats; - } - - @Override - public boolean isClientClosed() { - return isClientClosed.getAsBoolean(); - } - - @Override - public ByteBufAllocator getByteBufAllocator() { - return allocator; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerEntry.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerEntry.java deleted file mode 100644 index ca1a20cca7a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerEntry.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.InputStream; -import org.apache.bookkeeper.client.impl.LedgerEntryImpl; - -/** - * Mocked BK {@link LedgerEntry}. Used by {@link MockLedgerHandle}. - */ -public class MockLedgerEntry extends LedgerEntry { - - final long ledgerId; - final long entryId; - final byte[] data; - - public MockLedgerEntry(long ledgerId, long entryId, byte[] data) { - super(LedgerEntryImpl.create(ledgerId, entryId, data.length, Unpooled.wrappedBuffer(data))); - this.ledgerId = ledgerId; - this.entryId = entryId; - this.data = data; - } - - @Override - public long getLedgerId() { - return ledgerId; - } - - @Override - public long getEntryId() { - return entryId; - } - - @Override - public long getLength() { - return data.length; - } - - @Override - public byte[] getEntry() { - return data; - } - - @Override - public ByteBuf getEntryBuffer() { - return Unpooled.wrappedBuffer(data); - } - - @Override - public InputStream getEntryInputStream() { - return null; - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerHandle.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerHandle.java deleted file mode 100644 index f693c78783e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerHandle.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.security.GeneralSecurityException; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.RejectedExecutionException; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.CloseCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LastConfirmedAndEntry; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.client.impl.LedgerEntryImpl; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Mock BK {@link LedgerHandle}. Used by {@link MockBookKeeper}. - */ -public class MockLedgerHandle extends LedgerHandle { - - final ArrayList entries = Lists.newArrayList(); - final MockBookKeeper bk; - final long id; - final DigestType digest; - final byte[] passwd; - final ReadHandle readHandle; - long lastEntry = -1; - boolean fenced = false; - - MockLedgerHandle(MockBookKeeper bk, long id, DigestType digest, byte[] passwd) throws GeneralSecurityException { - super(bk.getClientCtx(), id, - new Versioned<>(createMetadata(digest, passwd), new LongVersion(0L)), - digest, passwd, WriteFlag.NONE); - this.bk = bk; - this.id = id; - this.digest = digest; - this.passwd = Arrays.copyOf(passwd, passwd.length); - - readHandle = new MockReadHandle(bk, id, getLedgerMetadata(), entries); - } - - @Override - public void asyncClose(CloseCallback cb, Object ctx) { - if (bk.getProgrammedFailStatus()) { - cb.closeComplete(bk.failReturnCode, this, ctx); - return; - } - - fenced = true; - try { - executeOrdered(() -> cb.closeComplete(0, this, ctx)); - } catch (RejectedExecutionException e) { - cb.closeComplete(0, this, ctx); - } - - } - - @Override - public void asyncReadEntries(final long firstEntry, final long lastEntry, final ReadCallback cb, final Object ctx) { - if (bk.isStopped()) { - cb.readComplete(-1, MockLedgerHandle.this, null, ctx); - return; - } - - executeOrdered(new Runnable() { - public void run() { - if (bk.getProgrammedFailStatus()) { - cb.readComplete(bk.failReturnCode, MockLedgerHandle.this, null, ctx); - return; - } else if (bk.isStopped()) { - if (log.isDebugEnabled()) { - log.debug("Bookkeeper is closed!"); - } - cb.readComplete(-1, MockLedgerHandle.this, null, ctx); - return; - } - - if (log.isDebugEnabled()) { - log.debug("readEntries: first={} last={} total={}", - firstEntry, lastEntry, entries.size()); - } - final Queue seq = new ArrayDeque(); - long entryId = firstEntry; - while (entryId <= lastEntry && entryId < entries.size()) { - seq.add(new LedgerEntry(entries.get((int) entryId++).duplicate())); - } - - if (log.isDebugEnabled()) { - log.debug("Entries read: {}", seq); - } - - try { - Thread.sleep(1); - } catch (InterruptedException e) { - } - - cb.readComplete(0, MockLedgerHandle.this, new Enumeration() { - public boolean hasMoreElements() { - return !seq.isEmpty(); - } - - public LedgerEntry nextElement() { - return seq.remove(); - } - - }, ctx); - } - }); - } - - @Override - public long addEntry(byte[] data) throws InterruptedException, BKException { - try { - bk.checkProgrammedFail(); - } catch (BKException e) { - fenced = true; - throw e; - } - - if (fenced) { - throw BKException.create(BKException.Code.LedgerFencedException); - } - - if (bk.isStopped()) { - throw BKException.create(BKException.Code.NoBookieAvailableException); - } - - lastEntry = entries.size(); - entries.add(LedgerEntryImpl.create(ledgerId, lastEntry, data.length, Unpooled.wrappedBuffer(data))); - return lastEntry; - } - - @Override - public void asyncAddEntry(final byte[] data, final AddCallback cb, final Object ctx) { - asyncAddEntry(data, 0, data.length, cb, ctx); - } - - @Override - public void asyncAddEntry(final byte[] data, final int offset, final int length, final AddCallback cb, - final Object ctx) { - asyncAddEntry(Unpooled.wrappedBuffer(data, offset, length), cb, ctx); - } - - @Override - public void asyncAddEntry(final ByteBuf data, final AddCallback cb, final Object ctx) { - if (bk.isStopped()) { - cb.addComplete(-1, MockLedgerHandle.this, INVALID_ENTRY_ID, ctx); - return; - } - - data.retain(); - executeOrdered(new Runnable() { - public void run() { - if (bk.getProgrammedFailStatus()) { - fenced = true; - data.release(); - cb.addComplete(bk.failReturnCode, MockLedgerHandle.this, INVALID_ENTRY_ID, ctx); - return; - } - if (bk.isStopped()) { - data.release(); - cb.addComplete(-1, MockLedgerHandle.this, INVALID_ENTRY_ID, ctx); - return; - } - - try { - Thread.sleep(1); - } catch (InterruptedException e) { - } - - if (fenced) { - data.release(); - cb.addComplete(BKException.Code.LedgerFencedException, MockLedgerHandle.this, - LedgerHandle.INVALID_ENTRY_ID, ctx); - } else { - lastEntry = entries.size(); - byte[] storedData = new byte[data.readableBytes()]; - data.readBytes(storedData); - entries.add(LedgerEntryImpl.create(ledgerId, lastEntry, - storedData.length, Unpooled.wrappedBuffer(storedData))); - data.release(); - cb.addComplete(0, MockLedgerHandle.this, lastEntry, ctx); - } - } - }); - } - - @Override - public long getId() { - return ledgerId; - } - - @Override - public long getLastAddConfirmed() { - return lastEntry; - } - - @Override - public long getLength() { - long length = 0; - for (LedgerEntryImpl entry : entries) { - length += entry.getLength(); - } - - return length; - } - - - // ReadHandle interface - @Override - public CompletableFuture readAsync(long firstEntry, long lastEntry) { - return readHandle.readAsync(firstEntry, lastEntry); - } - - @Override - public CompletableFuture readUnconfirmedAsync(long firstEntry, long lastEntry) { - return readHandle.readUnconfirmedAsync(firstEntry, lastEntry); - } - - @Override - public CompletableFuture readLastAddConfirmedAsync() { - return readHandle.readLastAddConfirmedAsync(); - } - - @Override - public CompletableFuture tryReadLastAddConfirmedAsync() { - return readHandle.tryReadLastAddConfirmedAsync(); - } - - @Override - public boolean isClosed() { - return readHandle.isClosed(); - } - - @Override - public CompletableFuture readLastAddConfirmedAndEntryAsync(long entryId, - long timeOutInMillis, - boolean parallel) { - return readHandle.readLastAddConfirmedAndEntryAsync(entryId, timeOutInMillis, parallel); - } - - private static LedgerMetadata createMetadata(DigestType digest, byte[] passwd) { - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId()); - return LedgerMetadataBuilder.create() - .withId(124L).withDigestType(digest.toApiDigestType()) - .withPassword(passwd) - .newEnsembleEntry(0L, ensemble) - .build(); - } - - private static final Logger log = LoggerFactory.getLogger(MockLedgerHandle.class); - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockReadHandle.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockReadHandle.java deleted file mode 100644 index fac6192a537..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockReadHandle.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.api.LastConfirmedAndEntry; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.LedgerEntry; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.impl.LedgerEntriesImpl; -import org.apache.bookkeeper.client.impl.LedgerEntryImpl; - - -/** - * Mock implementation of ReadHandle. - */ -@Slf4j -class MockReadHandle implements ReadHandle { - private final MockBookKeeper bk; - private final long ledgerId; - private final LedgerMetadata metadata; - private final List entries; - - MockReadHandle(MockBookKeeper bk, long ledgerId, LedgerMetadata metadata, List entries) { - this.bk = bk; - this.ledgerId = ledgerId; - this.metadata = metadata; - this.entries = entries; - } - - @Override - public CompletableFuture readAsync(long firstEntry, long lastEntry) { - CompletableFuture promise = new CompletableFuture<>(); - if (bk.isStopped()) { - promise.completeExceptionally(new BKException.BKClientClosedException()); - return promise; - } - - bk.orderedExecutor.chooseThread().execute(() -> { - if (bk.getProgrammedFailStatus()) { - promise.completeExceptionally(BKException.create(bk.failReturnCode)); - return; - } else if (bk.isStopped()) { - promise.completeExceptionally(new BKException.BKClientClosedException()); - return; - } - - if (log.isDebugEnabled()) { - log.debug("readEntries: first={} last={} total={}", firstEntry, lastEntry, entries.size()); - } - List seq = new ArrayList<>(); - long entryId = firstEntry; - while (entryId <= lastEntry && entryId < entries.size()) { - seq.add(entries.get((int) entryId++).duplicate()); - } - if (log.isDebugEnabled()) { - log.debug("Entries read: {}", seq); - } - promise.complete(LedgerEntriesImpl.create(seq)); - }); - return promise; - - } - - @Override - public CompletableFuture readUnconfirmedAsync(long firstEntry, long lastEntry) { - return readAsync(firstEntry, lastEntry); - } - - @Override - public CompletableFuture readLastAddConfirmedAsync() { - return CompletableFuture.completedFuture(getLastAddConfirmed()); - } - - @Override - public CompletableFuture tryReadLastAddConfirmedAsync() { - return readLastAddConfirmedAsync(); - } - - @Override - public long getLastAddConfirmed() { - return entries.get(entries.size() - 1).getEntryId(); - } - - @Override - public long getLength() { - long length = 0; - for (LedgerEntryImpl entry : entries) { - length += entry.getLength(); - } - - return length; - } - - @Override - public boolean isClosed() { - return metadata.isClosed(); - } - - @Override - public CompletableFuture readLastAddConfirmedAndEntryAsync(long entryId, - long timeOutInMillis, - boolean parallel) { - CompletableFuture promise = new CompletableFuture<>(); - promise.completeExceptionally(new UnsupportedOperationException("Long poll not implemented")); - return promise; - } - - // Handle interface - @Override - public long getId() { - return ledgerId; - } - - @Override - public CompletableFuture closeAsync() { - return CompletableFuture.completedFuture(null); - } - - @Override - public LedgerMetadata getLedgerMetadata() { - return metadata; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ParallelLedgerRecoveryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ParallelLedgerRecoveryTest.java deleted file mode 100644 index 4efc4465e38..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ParallelLedgerRecoveryTest.java +++ /dev/null @@ -1,792 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCounted; -import java.io.IOException; -import java.util.Enumeration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.exceptions.Code; -import org.apache.bookkeeper.meta.exceptions.MetadataException; -import org.apache.bookkeeper.meta.zk.ZKMetadataBookieDriver; -import org.apache.bookkeeper.meta.zk.ZKMetadataClientDriver; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.LedgerMetadataListener; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.Processor; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.lang3.mutable.MutableInt; -import org.apache.zookeeper.AsyncCallback.VoidCallback; -import org.junit.After; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test parallel ledger recovery. - */ -public class ParallelLedgerRecoveryTest extends BookKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(ParallelLedgerRecoveryTest.class); - - static class TestLedgerManager implements LedgerManager { - - final LedgerManager lm; - volatile CountDownLatch waitLatch = null; - final ExecutorService executorService; - - TestLedgerManager(LedgerManager lm) { - this.lm = lm; - this.executorService = Executors.newSingleThreadExecutor(); - } - - void setLatch(CountDownLatch waitLatch) { - this.waitLatch = waitLatch; - } - - @Override - public CompletableFuture> createLedgerMetadata( - long ledgerId, LedgerMetadata metadata) { - return lm.createLedgerMetadata(ledgerId, metadata); - } - - @Override - public CompletableFuture removeLedgerMetadata(long ledgerId, Version version) { - return lm.removeLedgerMetadata(ledgerId, version); - } - - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - return lm.readLedgerMetadata(ledgerId); - } - - @Override - public LedgerRangeIterator getLedgerRanges(long zkOpTimeoutMs) { - return lm.getLedgerRanges(zkOpTimeoutMs); - } - - @Override - public CompletableFuture> writeLedgerMetadata(long ledgerId, LedgerMetadata metadata, - Version currentVersion) { - final CountDownLatch cdl = waitLatch; - if (null != cdl) { - CompletableFuture> promise = new CompletableFuture<>(); - executorService.submit(new Runnable() { - @Override - public void run() { - try { - cdl.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Interrupted on waiting latch : ", e); - } - lm.writeLedgerMetadata(ledgerId, metadata, currentVersion) - .whenComplete((metadata, exception) -> { - if (exception != null) { - promise.completeExceptionally(exception); - } else { - promise.complete(metadata); - } - }); - } - }); - return promise; - } else { - return lm.writeLedgerMetadata(ledgerId, metadata, currentVersion); - } - } - - @Override - public void registerLedgerMetadataListener(long ledgerId, LedgerMetadataListener listener) { - lm.registerLedgerMetadataListener(ledgerId, listener); - } - - @Override - public void unregisterLedgerMetadataListener(long ledgerId, LedgerMetadataListener listener) { - lm.unregisterLedgerMetadataListener(ledgerId, listener); - } - - @Override - public void asyncProcessLedgers(Processor processor, VoidCallback finalCb, Object context, - int successRc, int failureRc) { - lm.asyncProcessLedgers(processor, finalCb, context, successRc, failureRc); - } - - @Override - public void close() throws IOException { - lm.close(); - executorService.shutdown(); - } - } - - static class TestLedgerManagerFactory extends HierarchicalLedgerManagerFactory { - @Override - public LedgerManager newLedgerManager() { - return new TestLedgerManager(super.newLedgerManager()); - } - } - - static class TestMetadataClientDriver extends ZKMetadataClientDriver { - - @Override - public synchronized LedgerManagerFactory getLedgerManagerFactory() throws MetadataException { - if (null == lmFactory) { - try { - lmFactory = new TestLedgerManagerFactory() - .initialize(conf, layoutManager, TestLedgerManagerFactory.CUR_VERSION); - } catch (IOException e) { - throw new MetadataException(Code.METADATA_SERVICE_ERROR, e); - } - } - return lmFactory; - } - } - - static class TestMetadataBookieDriver extends ZKMetadataBookieDriver { - - @Override - public synchronized LedgerManagerFactory getLedgerManagerFactory() throws MetadataException { - if (null == lmFactory) { - try { - lmFactory = new TestLedgerManagerFactory() - .initialize(conf, layoutManager, TestLedgerManagerFactory.CUR_VERSION); - } catch (IOException e) { - throw new MetadataException(Code.METADATA_SERVICE_ERROR, e); - } - } - return lmFactory; - } - } - - final DigestType digestType; - - public ParallelLedgerRecoveryTest() throws Exception { - super(3); - - this.digestType = DigestType.CRC32; - } - - @Override - protected void startBKCluster(String metadataServiceUri) throws Exception { - MetadataDrivers.registerClientDriver("zk", TestMetadataClientDriver.class, true); - MetadataDrivers.registerBookieDriver("zk", TestMetadataBookieDriver.class, true); - baseConf.setLedgerManagerFactoryClass(TestLedgerManagerFactory.class); - baseClientConf.setLedgerManagerFactoryClass(TestLedgerManagerFactory.class); - baseClientConf.setReadEntryTimeout(60000); - baseClientConf.setAddEntryTimeout(60000); - - super.startBKCluster(metadataServiceUri); - } - - @After - @Override - public void tearDown() throws Exception { - try { - super.tearDown(); - } finally { - MetadataDrivers.registerClientDriver("zk", ZKMetadataClientDriver.class, true); - MetadataDrivers.registerBookieDriver("zk", ZKMetadataBookieDriver.class, true); - } - } - - @Test - public void testRecoverBeforeWriteMetadata1() throws Exception { - rereadDuringRecovery(true, 1, false, false); - } - - @Test - public void testRecoverBeforeWriteMetadata2() throws Exception { - rereadDuringRecovery(true, 3, false, false); - } - - @Test - public void testRecoverBeforeWriteMetadata3() throws Exception { - rereadDuringRecovery(false, 1, false, false); - } - - @Test - public void testRecoverBeforeWriteMetadata4() throws Exception { - rereadDuringRecovery(false, 3, false, false); - } - - @Test - public void testRereadDuringRecovery1() throws Exception { - rereadDuringRecovery(true, 1, true, false); - } - - @Test - public void testRereadDuringRecovery2() throws Exception { - rereadDuringRecovery(true, 3, true, false); - } - - @Test - public void testRereadDuringRecovery3() throws Exception { - rereadDuringRecovery(false, 1, true, false); - } - - @Test - public void testRereadDuringRecovery4() throws Exception { - rereadDuringRecovery(false, 3, true, false); - } - - @Test - public void testConcurrentRecovery1() throws Exception { - rereadDuringRecovery(true, 1, true, false); - } - - @Test - public void testConcurrentRecovery2() throws Exception { - rereadDuringRecovery(true, 3, true, false); - } - - @Test - public void testConcurrentRecovery3() throws Exception { - rereadDuringRecovery(false, 1, true, false); - } - - @Test - public void testConcurrentRecovery4() throws Exception { - rereadDuringRecovery(false, 3, true, false); - } - - private void rereadDuringRecovery(boolean parallelRead, int batchSize, - boolean updateMetadata, boolean close) throws Exception { - ClientConfiguration newConf = new ClientConfiguration(); - newConf.addConfiguration(baseClientConf); - newConf.setEnableParallelRecoveryRead(parallelRead); - newConf.setRecoveryReadBatchSize(batchSize); - BookKeeper newBk = new BookKeeper(newConf); - - TestLedgerManager tlm = (TestLedgerManager) newBk.getUnderlyingLedgerManager(); - - final LedgerHandle lh = newBk.createLedger(numBookies, 2, 2, digestType, "".getBytes()); - CountDownLatch latch1 = new CountDownLatch(1); - CountDownLatch latch2 = new CountDownLatch(1); - sleepBookie(lh.getCurrentEnsemble().get(0), latch1); - sleepBookie(lh.getCurrentEnsemble().get(1), latch2); - - int numEntries = (numBookies * 3) + 1; - final AtomicInteger numPendingAdds = new AtomicInteger(numEntries); - final CountDownLatch addDone = new CountDownLatch(1); - for (int i = 0; i < numEntries; i++) { - lh.asyncAddEntry(("" + i).getBytes(), new org.apache.bookkeeper.client.AsyncCallback.AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - if (BKException.Code.OK != rc) { - addDone.countDown(); - return; - } - if (numPendingAdds.decrementAndGet() == 0) { - addDone.countDown(); - } - } - }, null); - } - latch1.countDown(); - latch2.countDown(); - addDone.await(10, TimeUnit.SECONDS); - assertEquals(0, numPendingAdds.get()); - - LOG.info("Added {} entries to ledger {}.", numEntries, lh.getId()); - - long ledgerLenth = lh.getLength(); - - LedgerHandle recoverLh = newBk.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(BookieProtocol.INVALID_ENTRY_ID, recoverLh.getLastAddPushed()); - assertEquals(BookieProtocol.INVALID_ENTRY_ID, recoverLh.getLastAddConfirmed()); - assertEquals(0, recoverLh.getLength()); - - LOG.info("OpenLedgerNoRecovery {}.", lh.getId()); - - final CountDownLatch metadataLatch = new CountDownLatch(1); - - tlm.setLatch(metadataLatch); - - final CountDownLatch recoverLatch = new CountDownLatch(1); - final AtomicBoolean success = new AtomicBoolean(false); - ((ReadOnlyLedgerHandle) recoverLh).recover(new GenericCallback() { - @Override - public void operationComplete(int rc, Void result) { - LOG.info("Recovering ledger {} completed : {}.", lh.getId(), rc); - success.set(BKException.Code.OK == rc); - recoverLatch.countDown(); - } - }); - - // clear the metadata latch - tlm.setLatch(null); - - if (updateMetadata) { - if (close) { - LOG.info("OpenLedger {} to close.", lh.getId()); - LedgerHandle newRecoverLh = newBk.openLedger(lh.getId(), digestType, "".getBytes()); - newRecoverLh.close(); - } else { - LOG.info("OpenLedgerNoRecovery {} again.", lh.getId()); - LedgerHandle newRecoverLh = newBk.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(BookieProtocol.INVALID_ENTRY_ID, newRecoverLh.getLastAddPushed()); - assertEquals(BookieProtocol.INVALID_ENTRY_ID, newRecoverLh.getLastAddConfirmed()); - - // mark the ledger as in recovery to update version. - ClientUtil.transformMetadata(newBk.getClientCtx(), newRecoverLh.getId(), - (metadata) -> LedgerMetadataBuilder.from(metadata).withInRecoveryState().build()); - - newRecoverLh.close(); - LOG.info("Updated ledger manager {}.", newRecoverLh.getLedgerMetadata()); - } - } - - // resume metadata operation on recoverLh - metadataLatch.countDown(); - - LOG.info("Resume metadata update."); - - // wait until recover completed - recoverLatch.await(20, TimeUnit.SECONDS); - assertTrue(success.get()); - assertEquals(numEntries - 1, recoverLh.getLastAddPushed()); - assertEquals(numEntries - 1, recoverLh.getLastAddConfirmed()); - assertEquals(ledgerLenth, recoverLh.getLength()); - assertTrue(recoverLh.getLedgerMetadata().isClosed()); - - Enumeration enumeration = recoverLh.readEntries(0, numEntries - 1); - int numReads = 0; - while (enumeration.hasMoreElements()) { - LedgerEntry entry = enumeration.nextElement(); - assertEquals((long) numReads, entry.getEntryId()); - assertEquals(numReads, Integer.parseInt(new String(entry.getEntry()))); - ++numReads; - } - assertEquals(numEntries, numReads); - - recoverLh.close(); - newBk.close(); - } - - @Test - public void testRecoveryOnEntryGap() throws Exception { - byte[] passwd = "recovery-on-entry-gap".getBytes(UTF_8); - LedgerHandle lh = bkc.createLedger(1, 1, 1, DigestType.CRC32, passwd); - for (int i = 0; i < 10; i++) { - lh.addEntry(("recovery-on-entry-gap-" + i).getBytes(UTF_8)); - } - - // simulate ledger writer failure on concurrent writes causing gaps - - long entryId = 14; - long lac = 8; - byte[] data = "recovery-on-entry-gap-gap".getBytes(UTF_8); - ReferenceCounted toSend = - lh.macManager.computeDigestAndPackageForSending( - entryId, lac, lh.getLength() + 100, Unpooled.wrappedBuffer(data, 0, data.length), - new byte[20], 0); - final CountDownLatch addLatch = new CountDownLatch(1); - final AtomicBoolean addSuccess = new AtomicBoolean(false); - LOG.info("Add entry {} with lac = {}", entryId, lac); - - bkc.getBookieClient().addEntry(lh.getCurrentEnsemble().get(0), - lh.getId(), lh.ledgerKey, entryId, toSend, - new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, - BookieId addr, Object ctx) { - addSuccess.set(BKException.Code.OK == rc); - addLatch.countDown(); - } - }, 0, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - addLatch.await(); - assertTrue("add entry 14 should succeed", addSuccess.get()); - - ClientConfiguration newConf = new ClientConfiguration(); - newConf.addConfiguration(baseClientConf); - newConf.setEnableParallelRecoveryRead(true); - newConf.setRecoveryReadBatchSize(10); - - BookKeeper newBk = new BookKeeper(newConf); - - final LedgerHandle recoverLh = - newBk.openLedgerNoRecovery(lh.getId(), DigestType.CRC32, passwd); - - assertEquals("wrong lac found", 8L, recoverLh.getLastAddConfirmed()); - - final CountDownLatch recoverLatch = new CountDownLatch(1); - final AtomicLong newLac = new AtomicLong(-1); - final AtomicBoolean isMetadataClosed = new AtomicBoolean(false); - final AtomicInteger numSuccessCalls = new AtomicInteger(0); - final AtomicInteger numFailureCalls = new AtomicInteger(0); - ((ReadOnlyLedgerHandle) recoverLh).recover(new GenericCallback() { - @Override - public void operationComplete(int rc, Void result) { - if (BKException.Code.OK == rc) { - newLac.set(recoverLh.getLastAddConfirmed()); - isMetadataClosed.set(recoverLh.getLedgerMetadata().isClosed()); - numSuccessCalls.incrementAndGet(); - } else { - numFailureCalls.incrementAndGet(); - } - recoverLatch.countDown(); - } - }); - recoverLatch.await(); - assertEquals("wrong lac found", 9L, newLac.get()); - assertTrue("metadata isn't closed after recovery", isMetadataClosed.get()); - Thread.sleep(5000); - assertEquals("recovery callback should be triggered only once", 1, numSuccessCalls.get()); - assertEquals("recovery callback should be triggered only once", 0, numFailureCalls.get()); - } - - static class DelayResponseBookie extends TestBookieImpl { - - static final class WriteCallbackEntry { - - private final WriteCallback cb; - private final int rc; - private final long ledgerId; - private final long entryId; - private final BookieId addr; - private final Object ctx; - - WriteCallbackEntry(WriteCallback cb, - int rc, long ledgerId, long entryId, - BookieId addr, Object ctx) { - this.cb = cb; - this.rc = rc; - this.ledgerId = ledgerId; - this.entryId = entryId; - this.addr = addr; - this.ctx = ctx; - } - - public void callback() { - cb.writeComplete(rc, ledgerId, entryId, addr, ctx); - } - } - - private final AtomicBoolean delayAddResponse = new AtomicBoolean(false); - private final AtomicBoolean delayReadResponse = new AtomicBoolean(false); - private final AtomicLong delayReadOnEntry = new AtomicLong(-1234L); - private volatile CountDownLatch delayReadLatch = null; - private final LinkedBlockingQueue delayQueue = - new LinkedBlockingQueue(); - - public DelayResponseBookie(ServerConfiguration conf) - throws Exception { - super(conf); - } - - @Override - public void addEntry(ByteBuf entry, boolean ackBeforeSync, final WriteCallback cb, Object ctx, byte[] masterKey) - throws IOException, BookieException, InterruptedException { - super.addEntry(entry, ackBeforeSync, new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, - BookieId addr, Object ctx) { - if (delayAddResponse.get()) { - delayQueue.add(new WriteCallbackEntry(cb, rc, ledgerId, entryId, addr, ctx)); - } else { - cb.writeComplete(rc, ledgerId, entryId, addr, ctx); - } - } - }, ctx, masterKey); - } - - @Override - public ByteBuf readEntry(long ledgerId, long entryId) throws IOException, NoLedgerException, BookieException { - LOG.info("ReadEntry {} - {}", ledgerId, entryId); - if (delayReadResponse.get() && delayReadOnEntry.get() == entryId) { - CountDownLatch latch = delayReadLatch; - if (null != latch) { - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - // no-op - } - } - } - return super.readEntry(ledgerId, entryId); - } - - void delayAdd(boolean delayed) { - this.delayAddResponse.set(delayed); - } - - void delayRead(boolean delayed, long entryId, CountDownLatch delayReadLatch) { - this.delayReadResponse.set(delayed); - this.delayReadOnEntry.set(entryId); - this.delayReadLatch = delayReadLatch; - } - - } - - @Test - public void testRecoveryWhenClosingLedgerHandle() throws Exception { - byte[] passwd = "recovery-when-closing-ledger-handle".getBytes(UTF_8); - - ClientConfiguration newConf = new ClientConfiguration(); - newConf.addConfiguration(baseClientConf); - newConf.setEnableParallelRecoveryRead(true); - newConf.setRecoveryReadBatchSize(1); - newConf.setAddEntryTimeout(9999999); - newConf.setReadEntryTimeout(9999999); - - final BookKeeper newBk0 = new BookKeeper(newConf); - final LedgerHandle lh0 = newBk0.createLedger(1, 1, 1, digestType, passwd); - - final BookKeeper newBk1 = new BookKeeper(newConf); - final LedgerHandle lh1 = newBk1.openLedgerNoRecovery(lh0.getId(), digestType, passwd); - final TestLedgerManager tlm1 = (TestLedgerManager) newBk1.getUnderlyingLedgerManager(); - - final BookKeeper readBk = new BookKeeper(newConf); - final LedgerHandle readLh = readBk.openLedgerNoRecovery(lh0.getId(), digestType, passwd); - - LOG.info("Create ledger {}", lh0.getId()); - - // 0) place the bookie with a fake bookie - BookieId address = lh0.getCurrentEnsemble().get(0); - ServerConfiguration conf = killBookie(address); - conf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - DelayResponseBookie fakeBookie = new DelayResponseBookie(conf); - startAndAddBookie(conf, fakeBookie); - - // 1) bk0 write two entries - lh0.addEntry("entry-0".getBytes(UTF_8)); - lh0.addEntry("entry-1".getBytes(UTF_8)); - - // 2) readBk read last add confirmed - long lac = readLh.readLastConfirmed(); - assertEquals(0L, lac); - lac = lh1.readLastConfirmed(); - assertEquals(0L, lac); - - final CountDownLatch addLatch = new CountDownLatch(3); - final AtomicInteger numAddFailures = new AtomicInteger(0); - // 3) bk0 write more entries in parallel - fakeBookie.delayAdd(true); - for (int i = 2; i < 5; i++) { - lh0.asyncAddEntry(("entry-" + i).getBytes(UTF_8), new AsyncCallback.AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - if (BKException.Code.OK != rc) { - numAddFailures.incrementAndGet(); - } - addLatch.countDown(); - } - }, null); - } - while (fakeBookie.delayQueue.size() < 3) { - // wait until all add requests are queued - Thread.sleep(100); - } - - // 4) lac moved to 1L - lac = readLh.readLastConfirmed(); - assertEquals(1L, lac); - lac = lh1.readLastConfirmed(); - assertEquals(1L, lac); - - // 5) bk1 is doing recovery, but the metadata update is delayed - final CountDownLatch readLatch = new CountDownLatch(1); - fakeBookie.delayAdd(false); - fakeBookie.delayRead(true, 3L, readLatch); - final CountDownLatch metadataLatch = new CountDownLatch(1); - tlm1.setLatch(metadataLatch); - final CountDownLatch recoverLatch = new CountDownLatch(1); - final AtomicBoolean recoverSuccess = new AtomicBoolean(false); - ((ReadOnlyLedgerHandle) lh1).recover(new GenericCallback() { - @Override - public void operationComplete(int rc, Void result) { - LOG.info("Recovering ledger {} completed : {}", lh1.getId(), rc); - recoverSuccess.set(BKException.Code.OK == rc); - recoverLatch.countDown(); - } - }); - Thread.sleep(2000); - readLatch.countDown(); - - // we don't expected lac being updated before we successfully marked the ledger in recovery - lac = readLh.readLastConfirmed(); - assertEquals(1L, lac); - - // 6) bk0 closes ledger before bk1 marks in recovery - lh0.close(); - assertEquals(1L, lh0.getLastAddConfirmed()); - - // 7) bk1 proceed recovery and succeed - metadataLatch.countDown(); - recoverLatch.await(); - assertTrue(recoverSuccess.get()); - assertEquals(1L, lh1.getLastAddConfirmed()); - - // 8) make sure we won't see lac advanced during ledger is closed by bk0 and recovered by bk1 - final AtomicLong lacHolder = new AtomicLong(-1234L); - final AtomicInteger rcHolder = new AtomicInteger(-1234); - final CountDownLatch doneLatch = new CountDownLatch(1); - - new ReadLastConfirmedOp(bkc.getBookieClient(), - readLh.distributionSchedule, - readLh.macManager, - readLh.ledgerId, - readLh.getLedgerMetadata().getAllEnsembles().lastEntry().getValue(), - readLh.ledgerKey, - new ReadLastConfirmedOp.LastConfirmedDataCallback() { - @Override - public void readLastConfirmedDataComplete(int rc, DigestManager.RecoveryData data) { - rcHolder.set(rc); - lacHolder.set(data.getLastAddConfirmed()); - doneLatch.countDown(); - } - }).initiate(); - doneLatch.await(); - assertEquals(BKException.Code.OK, rcHolder.get()); - assertEquals(1L, lacHolder.get()); - - newBk0.close(); - newBk1.close(); - readBk.close(); - } - - /** - * Validate ledger can recover with response: (Qw - Qa)+1. - * @throws Exception - */ - @Test - public void testRecoveryWithUnavailableBookie() throws Exception { - - byte[] passwd = "".getBytes(UTF_8); - ClientConfiguration newConf = new ClientConfiguration(); - newConf.addConfiguration(baseClientConf); - final BookKeeper readBk = new BookKeeper(newConf); - final BookKeeper newBk0 = new BookKeeper(newConf); - - /** - * Test Group-1 : Expected Response for recovery: Qr = (Qw - Qa)+1 = (3 - * -2) + 1 = 2 - */ - int ensembleSize = 3; - int writeQuorumSize = 3; - int ackQuormSize = 2; - LedgerHandle lh0 = newBk0.createLedger(ensembleSize, writeQuorumSize, ackQuormSize, DigestType.DUMMY, passwd); - LedgerHandle readLh = readBk.openLedgerNoRecovery(lh0.getId(), DigestType.DUMMY, passwd); - // Test 1: bookie response: OK, NO_SUCH_LEDGER_EXISTS, NOT_AVAILABLE - // Expected: Recovery successful Q(response) = 2 - int responseCode = readLACFromQuorum(readLh, BKException.Code.BookieHandleNotAvailableException, - BKException.Code.OK, BKException.Code.NoSuchLedgerExistsException); - assertEquals(responseCode, BKException.Code.OK); - // Test 2: bookie response: OK, NOT_AVAILABLE, NOT_AVAILABLE - // Expected: Recovery fail Q(response) = 1 - responseCode = readLACFromQuorum(readLh, BKException.Code.BookieHandleNotAvailableException, - BKException.Code.OK, BKException.Code.BookieHandleNotAvailableException); - assertEquals(responseCode, BKException.Code.BookieHandleNotAvailableException); - - /** - * Test Group-2 : Expected Response for recovery: Qr = (Qw - Qa)+1 = (2 - * -2) + 1 = 1 - */ - ensembleSize = 2; - writeQuorumSize = 2; - ackQuormSize = 2; - lh0 = newBk0.createLedger(ensembleSize, writeQuorumSize, ackQuormSize, DigestType.DUMMY, passwd); - readLh = readBk.openLedgerNoRecovery(lh0.getId(), DigestType.DUMMY, passwd); - // Test 1: bookie response: OK, NOT_AVAILABLE - // Expected: Recovery successful Q(response) = 1 - responseCode = readLACFromQuorum(readLh, BKException.Code.BookieHandleNotAvailableException, - BKException.Code.OK); - assertEquals(responseCode, BKException.Code.OK); - - // Test 1: bookie response: OK, NO_SUCH_LEDGER_EXISTS - // Expected: Recovery successful Q(response) = 2 - responseCode = readLACFromQuorum(readLh, BKException.Code.NoSuchLedgerExistsException, BKException.Code.OK); - assertEquals(responseCode, BKException.Code.OK); - - // Test 3: bookie response: NOT_AVAILABLE, NOT_AVAILABLE - // Expected: Recovery fail Q(response) = 0 - responseCode = readLACFromQuorum(readLh, BKException.Code.BookieHandleNotAvailableException, - BKException.Code.BookieHandleNotAvailableException); - assertEquals(responseCode, BKException.Code.BookieHandleNotAvailableException); - - newBk0.close(); - readBk.close(); - } - - private int readLACFromQuorum(LedgerHandle ledger, int... bookieLACResponse) throws Exception { - MutableInt responseCode = new MutableInt(100); - CountDownLatch responseLatch = new CountDownLatch(1); - ReadLastConfirmedOp readLCOp = new ReadLastConfirmedOp( - bkc.getBookieClient(), - ledger.getDistributionSchedule(), - ledger.getDigestManager(), - ledger.getId(), - ledger.getLedgerMetadata().getAllEnsembles().lastEntry().getValue(), - ledger.getLedgerKey(), - new ReadLastConfirmedOp.LastConfirmedDataCallback() { - @Override - public void readLastConfirmedDataComplete(int rc, DigestManager.RecoveryData data) { - System.out.println("response = " + rc); - responseCode.setValue(rc); - responseLatch.countDown(); - } - }); - byte[] lac = new byte[Long.SIZE * 3]; - ByteBuf data = Unpooled.wrappedBuffer(lac, 0, lac.length); - int writerIndex = data.writerIndex(); - data.resetWriterIndex(); - data.writeLong(ledger.getId()); - data.writeLong(0L); - data.writerIndex(writerIndex); - for (int i = 0; i < bookieLACResponse.length; i++) { - readLCOp.readEntryComplete(bookieLACResponse[i], 0, 0, data, i); - } - responseLatch.await(); - return responseCode.intValue(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/PendingAddOpTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/PendingAddOpTest.java deleted file mode 100644 index 5fb318c51fe..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/PendingAddOpTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.proto.BookieClient; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link PendingAddOp}. - */ -public class PendingAddOpTest { - - private LedgerHandle lh; - private ClientContext mockClientContext; - - private ByteBuf payload; - - @Before - public void setup() { - BookKeeperClientStats clientStats = BookKeeperClientStats.newInstance(NullStatsLogger.INSTANCE); - BookieClient bookieClient = mock(BookieClient.class); - OrderedExecutor mainWorkerPool = mock(OrderedExecutor.class); - mockClientContext = mock(ClientContext.class); - when(mockClientContext.getBookieClient()).thenReturn(bookieClient); - when(mockClientContext.getConf()).thenReturn(ClientInternalConf.defaultValues()); - when(mockClientContext.getMainWorkerPool()).thenReturn(mainWorkerPool); - when(mockClientContext.getClientStats()).thenReturn(clientStats); - - lh = mock(LedgerHandle.class); - when(lh.getDistributionSchedule()) - .thenReturn(new RoundRobinDistributionSchedule(3, 3, 2)); - byte[] data = "test-pending-add-op".getBytes(UTF_8); - payload = Unpooled.wrappedBuffer(data); - payload.writerIndex(data.length); - } - - @Test - public void testExecuteAfterCancelled() { - AtomicInteger rcHolder = new AtomicInteger(-0xdead); - PendingAddOp op = PendingAddOp.create( - lh, mockClientContext, lh.getCurrentEnsemble(), - payload, WriteFlag.NONE, - (rc, handle, entryId, qwcLatency, ctx) -> { - rcHolder.set(rc); - }, null); - assertSame(lh, op.lh); - - // cancel the op. - op.submitCallback(Code.NotEnoughBookiesException); - // if a op is cancelled, it is not recycled until it has been run. - assertSame(lh, op.lh); - assertEquals(Code.NotEnoughBookiesException, rcHolder.get()); - - op.initiate(); - // after the op is run, the object is recycled. - assertNull(op.lh); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedAndEntryOpTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedAndEntryOpTest.java deleted file mode 100644 index 760f2490182..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedAndEntryOpTest.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.util.ReferenceCounted; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.ReadLastConfirmedAndEntryOp.LastConfirmedAndEntryCallback; -import org.apache.bookkeeper.client.api.LastConfirmedAndEntry; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.impl.LastConfirmedAndEntryImpl; -import org.apache.bookkeeper.client.impl.LedgerEntryImpl; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieClient; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback; -import org.apache.bookkeeper.proto.ReadLastConfirmedAndEntryContext; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.proto.checksum.DummyDigestManager; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.ByteBufList; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link ReadLastConfirmedAndEntryOp} with mocks. - */ -@Slf4j -public class ReadLastConfirmedAndEntryOpTest { - - private static final long LEDGERID = System.currentTimeMillis(); - - private final TestStatsProvider testStatsProvider = new TestStatsProvider(); - private BookKeeperClientStats clientStats; - private ClientContext mockClientCtx; - private BookieClient mockBookieClient; - private LedgerHandle mockLh; - private ScheduledExecutorService scheduler; - private OrderedScheduler orderedScheduler; - private ClientInternalConf internalConf; - private EnsemblePlacementPolicy placementPolicy; - private LedgerMetadata ledgerMetadata; - private DistributionSchedule distributionSchedule; - private DigestManager digestManager; - - @Before - public void setup() throws Exception { - // stats - clientStats = BookKeeperClientStats.newInstance(testStatsProvider.getStatsLogger("")); - // policy - ClientConfiguration conf = new ClientConfiguration(); - conf.setFirstSpeculativeReadLACTimeout(100); - conf.setMaxSpeculativeReadLACTimeout(200); - conf.setSpeculativeReadLACTimeoutBackoffMultiplier(2); - - internalConf = ClientInternalConf.fromConfig(conf); - - // metadata - ArrayList ensemble = new ArrayList<>(3); - for (int i = 0; i < 3; i++) { - ensemble.add(new BookieSocketAddress("127.0.0.1", 3181 + i).toBookieId()); - } - this.ledgerMetadata = LedgerMetadataBuilder.create() - .withId(124L).withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(2) - .withPassword(new byte[0]) - .withDigestType(DigestType.CRC32.toApiDigestType()) - .newEnsembleEntry(0L, ensemble).build(); - this.distributionSchedule = new RoundRobinDistributionSchedule(3, 2, 3); - // schedulers - this.scheduler = Executors.newSingleThreadScheduledExecutor(); - this.orderedScheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-ordered-scheduler") - .numThreads(1) - .build(); - - this.mockBookieClient = mock(BookieClient.class); - //this.mockPlacementPolicy = mock(EnsemblePlacementPolicy.class); - this.placementPolicy = new DefaultEnsemblePlacementPolicy(); - this.mockClientCtx = mock(ClientContext.class); - when(mockClientCtx.getBookieClient()).thenReturn(mockBookieClient); - when(mockClientCtx.getPlacementPolicy()).thenReturn(placementPolicy); - when(mockClientCtx.getConf()).thenReturn(internalConf); - when(mockClientCtx.getScheduler()).thenReturn(orderedScheduler); - when(mockClientCtx.getMainWorkerPool()).thenReturn(orderedScheduler); - when(mockClientCtx.getClientStats()).thenReturn(clientStats); - this.mockLh = mock(LedgerHandle.class); - - when(mockLh.getId()).thenReturn(LEDGERID); - when(mockLh.getCurrentEnsemble()).thenReturn(ensemble); - when(mockLh.getLedgerMetadata()).thenReturn(ledgerMetadata); - when(mockLh.getDistributionSchedule()).thenReturn(distributionSchedule); - digestManager = new DummyDigestManager(LEDGERID, false, UnpooledByteBufAllocator.DEFAULT); - when(mockLh.getDigestManager()).thenReturn(digestManager); - } - - @After - public void teardown() { - this.scheduler.shutdown(); - this.orderedScheduler.shutdown(); - } - - @Data - static class ReadLastConfirmedAndEntryHolder { - - private final BookieId address; - private final ReadEntryCallback callback; - private final ReadLastConfirmedAndEntryContext context; - - } - - /** - * Test case: handling different speculative responses. one speculative response might return a valid response - * with a read entry, while the other speculative response might return a valid response without an entry. - * {@link ReadLastConfirmedAndEntryOp} should handle both responses well. - * - *

This test case covers {@link https://github.com/apache/bookkeeper/issues/1476}. - */ - @Test - public void testSpeculativeResponses() throws Exception { - final long entryId = 2L; - final long lac = 1L; - - ByteBuf data = Unpooled.copiedBuffer("test-speculative-responses", UTF_8); - ReferenceCounted refCnt = digestManager.computeDigestAndPackageForSending( - entryId, lac, data.readableBytes(), data, new byte[20], 0); - - byte[] bytesWithDigest = null; - if (refCnt instanceof ByteBufList) { - ByteBufList dataWithDigest = (ByteBufList) refCnt; - bytesWithDigest = new byte[dataWithDigest.readableBytes()]; - assertEquals(bytesWithDigest.length, dataWithDigest.getBytes(bytesWithDigest)); - } - - final Map callbacks = - Collections.synchronizedMap(new HashMap<>()); - doAnswer(invocationOnMock -> { - BookieId address = invocationOnMock.getArgument(0); - ReadEntryCallback callback = invocationOnMock.getArgument(6); - ReadLastConfirmedAndEntryContext context = invocationOnMock.getArgument(7); - - ReadLastConfirmedAndEntryHolder holder = new ReadLastConfirmedAndEntryHolder(address, callback, context); - - log.info("Received read request to bookie {}", address); - - callbacks.put(address, holder); - return null; - }).when(mockBookieClient).readEntryWaitForLACUpdate(any(BookieId.class), - anyLong(), - anyLong(), - anyLong(), - anyLong(), - anyBoolean(), - any(ReadEntryCallback.class), - any() - ); - - CompletableFuture resultFuture = new CompletableFuture<>(); - LastConfirmedAndEntryCallback resultCallback = (rc, lastAddConfirmed, entry) -> { - if (Code.OK != rc) { - FutureUtils.completeExceptionally(resultFuture, BKException.create(rc)); - } else { - FutureUtils.complete(resultFuture, LastConfirmedAndEntryImpl.create(lastAddConfirmed, entry)); - } - }; - - ReadLastConfirmedAndEntryOp op = new ReadLastConfirmedAndEntryOp( - mockLh, mockClientCtx, mockLh.getCurrentEnsemble(), resultCallback, 1L, 10000); - op.initiate(); - - // wait until all speculative requests are sent - while (callbacks.size() < 3) { - log.info("Received {} read requests", callbacks.size()); - Thread.sleep(100); - } - - log.info("All speculative reads are outstanding now."); - - // once all the speculative reads are outstanding. complete the requests in following sequence: - - // 1) complete one bookie with empty response (OK, entryId = INVALID_ENTRY_ID) - // 2) complete second bookie with valid entry response. this will trigger double-release bug described in - // {@link https://github.com/apache/bookkeeper/issues/1476} - - Iterator> iter = callbacks.entrySet().iterator(); - assertTrue(iter.hasNext()); - Entry firstBookieEntry = iter.next(); - ReadLastConfirmedAndEntryHolder firstBookieHolder = firstBookieEntry.getValue(); - ReadLastConfirmedAndEntryContext firstContext = firstBookieHolder.context; - firstContext.setLastAddConfirmed(entryId); - firstBookieHolder.getCallback() - .readEntryComplete(Code.OK, LEDGERID, BookieProtocol.INVALID_ENTRY_ID, null, firstContext); - - // readEntryComplete above will release the entry impl back to the object pools. - // we want to make sure after the entry is recycled, it will not be mutated by any future callbacks. - LedgerEntryImpl entry = LedgerEntryImpl.create(LEDGERID, Long.MAX_VALUE); - - assertTrue(iter.hasNext()); - Entry secondBookieEntry = iter.next(); - ReadLastConfirmedAndEntryHolder secondBookieHolder = secondBookieEntry.getValue(); - ReadLastConfirmedAndEntryContext secondContext = secondBookieHolder.context; - secondContext.setLastAddConfirmed(entryId); - secondBookieHolder.getCallback().readEntryComplete( - Code.OK, LEDGERID, entryId, Unpooled.wrappedBuffer(bytesWithDigest), secondContext); - - // the recycled entry shouldn't be updated by any future callbacks. - assertNull(entry.getEntryBuffer()); - entry.close(); - - // wait for results - try (LastConfirmedAndEntry lacAndEntry = FutureUtils.result(resultFuture)) { - assertEquals(entryId, lacAndEntry.getLastAddConfirmed()); - assertNull(lacAndEntry.getEntry()); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedOpTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedOpTest.java deleted file mode 100644 index 954bdccca83..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedOpTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import com.google.common.collect.Lists; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests about ReadLastConfirmedOp. - */ -public class ReadLastConfirmedOpTest { - private static final Logger log = LoggerFactory.getLogger(ReadLastConfirmedOpTest.class); - private final BookieId bookie1 = new BookieSocketAddress("bookie1", 3181).toBookieId(); - private final BookieId bookie2 = new BookieSocketAddress("bookie2", 3181).toBookieId(); - - OrderedExecutor executor = null; - - @Before - public void setup() throws Exception { - executor = OrderedExecutor.newBuilder() - .name("BookKeeperClientWorker") - .numThreads(1) - .build(); - } - - @After - public void teardown() throws Exception { - if (executor != null) { - executor.shutdown(); - } - } - - /** - * Test for specific bug that was introduced with dcdd1e88. - */ - @Test - public void testBookieFailsAfterLedgerMissingOnFirst() throws Exception { - long ledgerId = 0xf00b; - List ensemble = Lists.newArrayList(bookie1, bookie2); - byte[] ledgerKey = new byte[0]; - - MockBookieClient bookieClient = new MockBookieClient(executor); - DistributionSchedule schedule = new RoundRobinDistributionSchedule(2, 2, 2); - DigestManager digestManager = DigestManager.instantiate(ledgerId, ledgerKey, - DigestType.CRC32C, - UnpooledByteBufAllocator.DEFAULT, - true /* useV2 */); - - CompletableFuture blocker = new CompletableFuture<>(); - bookieClient.setPreReadHook((bookie, lId, entryId) -> { - if (bookie.equals(bookie1)) { - return CompletableFuture.completedFuture(null); - } else { - return blocker; - } - }); - CompletableFuture promise = new CompletableFuture<>(); - ReadLastConfirmedOp op = new ReadLastConfirmedOp( - bookieClient, schedule, - digestManager, ledgerId, ensemble, - ledgerKey, - (rc, data) -> { - if (rc != BKException.Code.OK) { - promise.completeExceptionally( - BKException.create(rc)); - } else { - promise.complete(data); - } - }); - op.initiateWithFencing(); - - while (op.getNumResponsesPending() > 1) { - Thread.sleep(100); - } - blocker.completeExceptionally( - new BKException.BKBookieHandleNotAvailableException()); - promise.get(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/RoundRobinDistributionScheduleTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/RoundRobinDistributionScheduleTest.java deleted file mode 100644 index a9f44989363..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/RoundRobinDistributionScheduleTest.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.RoundRobinDistributionSchedule.writeSetFromValues; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Sets; -import java.util.BitSet; -import java.util.HashSet; -import java.util.Set; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test a round-robin distribution schedule. - */ -public class RoundRobinDistributionScheduleTest { - private static final Logger LOG = LoggerFactory.getLogger(RoundRobinDistributionScheduleTest.class); - - @Test - public void testDistributionSchedule() throws Exception { - RoundRobinDistributionSchedule schedule = new RoundRobinDistributionSchedule(3, 2, 5); - - DistributionSchedule.WriteSet wSet = schedule.getWriteSet(1); - assertEquals("Write set is wrong size", wSet.size(), 3); - DistributionSchedule.AckSet ackSet = schedule.getAckSet(); - assertFalse("Shouldn't ack yet", - ackSet.completeBookieAndCheck(wSet.get(0))); - assertFalse("Shouldn't ack yet", - ackSet.completeBookieAndCheck(wSet.get(0))); - assertTrue("Should ack after 2 unique", - ackSet.completeBookieAndCheck(wSet.get(2))); - assertTrue("Should still be acking", - ackSet.completeBookieAndCheck(wSet.get(1))); - } - - /** - * Test that coverage sets only respond as covered when it has - * heard from enough bookies that no ack quorum can exist without these bookies. - */ - @Test - public void testCoverageSets() { - int errors = 0; - for (int e = 6; e > 0; e--) { - for (int w = e; w > 0; w--) { - for (int a = w; a > 0; a--) { - errors += testCoverageForConfiguration(e, w, a); - } - } - } - assertEquals("Should be no errors", 0, errors); - } - - /** - * Build a boolean array of which nodes have not responded - * and thus are available to build a quorum. - */ - boolean[] buildAvailable(int ensemble, Set responses) { - boolean[] available = new boolean[ensemble]; - for (int i = 0; i < ensemble; i++) { - available[i] = !responses.contains(i); - } - return available; - } - - /** - * Check whether it is possible for a write to reach - * a quorum with a given set of nodes available. - */ - boolean canGetAckQuorum(int ensemble, int writeQuorum, int ackQuorum, boolean[] available) { - for (int i = 0; i < ensemble; i++) { - int count = 0; - for (int j = 0; j < writeQuorum; j++) { - if (available[(i + j) % ensemble]) { - count++; - } - } - if (count >= ackQuorum) { - return true; - } - } - return false; - } - - private int testCoverageForConfiguration(int ensemble, int writeQuorum, int ackQuorum) { - RoundRobinDistributionSchedule schedule = new RoundRobinDistributionSchedule( - writeQuorum, ackQuorum, ensemble); - Set indexes = new HashSet(); - for (int i = 0; i < ensemble; i++) { - indexes.add(i); - } - Set> subsets = Sets.powerSet(indexes); - - int errors = 0; - for (Set subset : subsets) { - DistributionSchedule.QuorumCoverageSet covSet = schedule.getCoverageSet(); - for (Integer i : subset) { - covSet.addBookie(i, BKException.Code.OK); - } - boolean covSetSays = covSet.checkCovered(); - - boolean[] nodesAvailable = buildAvailable(ensemble, subset); - boolean canGetAck = canGetAckQuorum(ensemble, writeQuorum, ackQuorum, nodesAvailable); - if (canGetAck == covSetSays) { - LOG.error("e{}:w{}:a{} available {} canGetAck {} covSetSays {}", - ensemble, writeQuorum, ackQuorum, - nodesAvailable, canGetAck, covSetSays); - errors++; - } - } - return errors; - } - - @Test - public void testMoveAndShift() { - DistributionSchedule.WriteSet w = writeSetFromValues(1, 2, 3, 4, 5); - w.moveAndShift(3, 1); - assertEquals(w, writeSetFromValues(1, 4, 2, 3, 5)); - - w = writeSetFromValues(1, 2, 3, 4, 5); - w.moveAndShift(1, 3); - assertEquals(w, writeSetFromValues(1, 3, 4, 2, 5)); - - w = writeSetFromValues(1, 2, 3, 4, 5); - w.moveAndShift(0, 4); - assertEquals(w, writeSetFromValues(2, 3, 4, 5, 1)); - - w = writeSetFromValues(1, 2, 3, 4, 5); - w.moveAndShift(0, 0); - assertEquals(w, writeSetFromValues(1, 2, 3, 4, 5)); - - w = writeSetFromValues(1, 2, 3, 4, 5); - w.moveAndShift(4, 4); - assertEquals(w, writeSetFromValues(1, 2, 3, 4, 5)); - } - - @Test - public void testGetEntriesStripedToTheBookie() { - - RoundRobinDistributionSchedule schedule; - BitSet entriesStriped; - - int ensSize = 3; - int writeQuorum = 3; - int ackQuorum = 3; - int startEntryId = 3; - int lastEntryId = 5; - schedule = new RoundRobinDistributionSchedule(writeQuorum, ackQuorum, ensSize); - - for (int bookieIndex = 0; bookieIndex < ensSize; bookieIndex++) { - entriesStriped = schedule.getEntriesStripedToTheBookie(bookieIndex, startEntryId, lastEntryId); - assertEquals("Cardinality", 3, entriesStriped.cardinality()); - for (int i = 0; i < entriesStriped.length(); i++) { - assertEquals("EntryAvailability", schedule.hasEntry((startEntryId + i), bookieIndex), - entriesStriped.get(i)); - } - } - - ensSize = 5; - writeQuorum = 3; - ackQuorum = 2; - startEntryId = 100; - lastEntryId = 122; - schedule = new RoundRobinDistributionSchedule(writeQuorum, ackQuorum, ensSize); - for (int bookieIndex = 0; bookieIndex < ensSize; bookieIndex++) { - entriesStriped = schedule.getEntriesStripedToTheBookie(bookieIndex, startEntryId, lastEntryId); - for (int i = 0; i < entriesStriped.length(); i++) { - assertEquals("EntryAvailability", schedule.hasEntry((startEntryId + i), bookieIndex), - entriesStriped.get(i)); - } - } - - schedule = new RoundRobinDistributionSchedule(2, 2, 3); - entriesStriped = schedule.getEntriesStripedToTheBookie(2, 0, 0); - assertEquals("Cardinality", 0, entriesStriped.cardinality()); - entriesStriped = schedule.getEntriesStripedToTheBookie(2, 3, 3); - assertEquals("Cardinality", 0, entriesStriped.cardinality()); - entriesStriped = schedule.getEntriesStripedToTheBookie(2, 4, 4); - assertEquals("Cardinality", 1, entriesStriped.cardinality()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/SlowBookieTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/SlowBookieTest.java deleted file mode 100644 index d77e7a1d7d3..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/SlowBookieTest.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieClientImpl; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.awaitility.Awaitility; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test a slow bookie. - */ -@SuppressWarnings("deprecation") -public class SlowBookieTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(SlowBookieTest.class); - - final byte[] entry = "Test Entry".getBytes(); - - public SlowBookieTest() { - super(4); - baseConf.setNumAddWorkerThreads(0); - baseConf.setNumReadWorkerThreads(0); - } - - @Test - public void testSlowBookie() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setReadTimeout(360) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - - LedgerHandle lh = bkc.createLedger(4, 3, 2, BookKeeper.DigestType.CRC32, new byte[] {}); - - byte[] entry = "Test Entry".getBytes(); - for (int i = 0; i < 10; i++) { - lh.addEntry(entry); - } - final CountDownLatch b0latch = new CountDownLatch(1); - final CountDownLatch b1latch = new CountDownLatch(1); - final CountDownLatch addEntrylatch = new CountDownLatch(1); - List curEns = lh.getCurrentEnsemble(); - try { - sleepBookie(curEns.get(0), b0latch); - for (int i = 0; i < 10; i++) { - lh.addEntry(entry); - } - sleepBookie(curEns.get(2), b1latch); // should cover all quorums - - final AtomicInteger i = new AtomicInteger(0xdeadbeef); - AsyncCallback.AddCallback cb = new AsyncCallback.AddCallback() { - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - i.set(rc); - addEntrylatch.countDown(); - } - }; - lh.asyncAddEntry(entry, cb, null); - - Awaitility.await().untilAsserted(() -> - assertEquals("Successfully added entry!", 0xdeadbeef, i.get())); - b0latch.countDown(); - b1latch.countDown(); - addEntrylatch.await(4000, TimeUnit.MILLISECONDS); - assertEquals("Failed to add entry!", BKException.Code.OK, i.get()); - } finally { - b0latch.countDown(); - b1latch.countDown(); - addEntrylatch.countDown(); - } - } - - @Test - public void testBookieFailureWithSlowBookie() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setReadTimeout(5) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - - byte[] pwd = new byte[] {}; - final LedgerHandle lh = bkc.createLedger(4, 3, 2, BookKeeper.DigestType.CRC32, pwd); - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failTest = new AtomicBoolean(false); - Thread t = new Thread() { - public void run() { - try { - while (!finished.get()) { - lh.addEntry(entry); - } - } catch (Exception e) { - LOG.error("Exception in add entry thread", e); - failTest.set(true); - } - } - }; - t.start(); - final CountDownLatch b0latch = new CountDownLatch(1); - - startNewBookie(); - sleepBookie(getBookie(0), b0latch); - - Thread.sleep(10000); - b0latch.countDown(); - - finished.set(true); - t.join(); - - assertFalse(failTest.get()); - - lh.close(); - - LedgerHandle lh2 = bkc.openLedger(lh.getId(), BookKeeper.DigestType.CRC32, pwd); - LedgerChecker lc = new LedgerChecker(bkc); - final CountDownLatch checklatch = new CountDownLatch(1); - final AtomicInteger numFragments = new AtomicInteger(-1); - lc.checkLedger(lh2, new GenericCallback>() { - public void operationComplete(int rc, Set badFragments) { - if (LOG.isDebugEnabled()) { - LOG.debug("Checked ledgers returned {} {}", rc, badFragments); - } - if (rc == BKException.Code.OK) { - numFragments.set(badFragments.size()); - } - checklatch.countDown(); - } - }); - checklatch.await(); - assertEquals("There should be no missing fragments", 0, numFragments.get()); - } - - @Test - public void testSlowBookieAndBackpressureOn() throws Exception { - final ClientConfiguration conf = new ClientConfiguration(); - conf.setReadTimeout(5) - .setAddEntryTimeout(1) - .setAddEntryQuorumTimeout(1) - .setNumChannelsPerBookie(1) - .setZkServers(zkUtil.getZooKeeperConnectString()) - .setClientWriteBufferLowWaterMark(1) - .setClientWriteBufferHighWaterMark(entry.length - 1) - .setWaitTimeoutOnBackpressureMillis(5000); - - final boolean expectWriteError = false; - final boolean expectFailedTest = false; - - try (LedgerHandle lh = doBackPressureTest(entry, conf, expectWriteError, expectFailedTest, 2000)) { - assertTrue(lh.readLastConfirmed() < 5); - } - } - - @Test - public void testSlowBookieAndFastFailOn() throws Exception { - final ClientConfiguration conf = new ClientConfiguration(); - conf.setReadTimeout(5) - .setAddEntryTimeout(1) - .setAddEntryQuorumTimeout(1) - .setNumChannelsPerBookie(1) - .setZkServers(zkUtil.getZooKeeperConnectString()) - .setClientWriteBufferLowWaterMark(1) - .setClientWriteBufferHighWaterMark(2) - .setWaitTimeoutOnBackpressureMillis(0); - - final boolean expectWriteError = true; - final boolean expectFailedTest = false; - - try (LedgerHandle lh = doBackPressureTest(entry, conf, expectWriteError, expectFailedTest, 1000)) { - assertTrue(lh.readLastConfirmed() < 5); - } - } - - @Test - public void testSlowBookieAndNoBackpressure() throws Exception { - final ClientConfiguration conf = new ClientConfiguration(); - conf.setReadTimeout(5) - .setAddEntryTimeout(1) - .setAddEntryQuorumTimeout(1) - .setNumChannelsPerBookie(1) - .setZkServers(zkUtil.getZooKeeperConnectString()) - .setClientWriteBufferLowWaterMark(1) - .setClientWriteBufferHighWaterMark(entry.length - 1) - .setWaitTimeoutOnBackpressureMillis(-1); - - final boolean expectWriteError = false; - final boolean expectFailedTest = false; - - try (LedgerHandle lh = doBackPressureTest(entry, conf, expectWriteError, expectFailedTest, 4000)) { - assertTrue(lh.readLastConfirmed() > 90); - } - } - - private LedgerHandle doBackPressureTest(byte[] entry, ClientConfiguration conf, - boolean expectWriteError, boolean expectFailedTest, - long sleepInMillis) throws Exception { - BookKeeper bkc = new BookKeeper(conf); - - byte[] pwd = new byte[] {}; - final LedgerHandle lh = bkc.createLedger(4, 3, 1, BookKeeper.DigestType.CRC32, pwd); - lh.addEntry(entry); - - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failTest = new AtomicBoolean(false); - final AtomicBoolean writeError = new AtomicBoolean(false); - Thread t = new Thread(() -> { - try { - int count = 0; - while (!finished.get()) { - lh.asyncAddEntry(entry, (rc, lh1, entryId, ctx) -> { - if (rc != BKException.Code.OK) { - finished.set(true); - writeError.set(true); - } - }, null); - if (++count > 100) { - finished.set(true); - } - } - } catch (Exception e) { - LOG.error("Exception in add entry thread", e); - failTest.set(true); - } - }); - final CountDownLatch b0latch = new CountDownLatch(1); - final CountDownLatch b0latch2 = new CountDownLatch(1); - - - sleepBookie(getBookie(0), b0latch); - sleepBookie(getBookie(1), b0latch2); - - setTargetChannelState(bkc, getBookie(0), 0, false); - setTargetChannelState(bkc, getBookie(1), 0, false); - - t.start(); - - Thread.sleep(sleepInMillis); - - finished.set(true); - - b0latch.countDown(); - b0latch2.countDown(); - setTargetChannelState(bkc, getBookie(0), 0, true); - setTargetChannelState(bkc, getBookie(1), 0, true); - - t.join(); - - assertEquals("write error", expectWriteError, writeError.get()); - assertEquals("test failure", expectFailedTest, failTest.get()); - - lh.close(); - - LedgerHandle lh2 = bkc.openLedger(lh.getId(), BookKeeper.DigestType.CRC32, pwd); - LedgerChecker lc = new LedgerChecker(bkc); - final CountDownLatch checkLatch = new CountDownLatch(1); - final AtomicInteger numFragments = new AtomicInteger(-1); - lc.checkLedger(lh2, (rc, fragments) -> { - if (LOG.isDebugEnabled()) { - LOG.debug("Checked ledgers returned {} {}", rc, fragments); - } - if (rc == BKException.Code.OK) { - numFragments.set(fragments.size()); - LOG.error("Checked ledgers returned {} {}", rc, fragments); - } - checkLatch.countDown(); - }); - checkLatch.await(); - assertEquals("There should be no missing fragments", 0, numFragments.get()); - - return lh2; - } - - private void setTargetChannelState(BookKeeper bkc, BookieId address, - long key, boolean writable) throws Exception { - ((BookieClientImpl) bkc.getBookieClient()).lookupClient(address).obtain((rc, pcbc) -> { - pcbc.setWritable(writable); - }, key); - } - - @Test - public void testWriteSetWriteableCheck() throws Exception { - final ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] pwd = new byte[]{}; - try (LedgerHandle lh = bkc.createLedger(4, 2, 2, BookKeeper.DigestType.CRC32, pwd)) { - lh.addEntry(entry); // [b0, b1] - long entryId = lh.addEntry(entry); // [b1, b2] - - long nextEntryId = entryId + 1; - RoundRobinDistributionSchedule schedule = new RoundRobinDistributionSchedule(2, 2, 4); - DistributionSchedule.WriteSet writeSet = schedule.getWriteSet(nextEntryId); - - // b2 or b3 is no more writeable - int slowBookieIndex = writeSet.get(ThreadLocalRandom.current().nextInt(writeSet.size())); - List curEns = lh.getCurrentEnsemble(); - - // Trigger connection to the bookie service first - bkc.getBookieInfo().get(curEns.get(slowBookieIndex)); - // then mock channel is not writable - setTargetChannelState(bkc, curEns.get(slowBookieIndex), 0, false); - - boolean isWriteable = lh.waitForWritable(writeSet, 0, 1000); - assertFalse("We should check b2,b3 both are not writeable", isWriteable); - } - } - - @Test - public void testManyBookieFailureWithSlowBookies() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setReadTimeout(5) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - BookKeeper bkc = new BookKeeper(conf); - - byte[] pwd = new byte[] {}; - final LedgerHandle lh = bkc.createLedger(4, 3, 2, BookKeeper.DigestType.CRC32, pwd); - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failTest = new AtomicBoolean(false); - Thread t = new Thread() { - public void run() { - try { - while (!finished.get()) { - lh.addEntry(entry); - Thread.sleep(1); - } - } catch (Exception e) { - LOG.error("Exception in add entry thread", e); - failTest.set(true); - } - } - }; - t.start(); - final CountDownLatch b0latch = new CountDownLatch(1); - final CountDownLatch b1latch = new CountDownLatch(1); - - startNewBookie(); - startNewBookie(); - - sleepBookie(getBookie(0), b0latch); - sleepBookie(getBookie(1), b1latch); - - Thread.sleep(10000); - b0latch.countDown(); - b1latch.countDown(); - finished.set(true); - t.join(); - - assertFalse(failTest.get()); - - lh.close(); - - LedgerHandle lh2 = bkc.openLedger(lh.getId(), BookKeeper.DigestType.CRC32, pwd); - LedgerChecker lc = new LedgerChecker(bkc); - final CountDownLatch checklatch = new CountDownLatch(1); - final AtomicInteger numFragments = new AtomicInteger(-1); - lc.checkLedger(lh2, new GenericCallback>() { - public void operationComplete(int rc, Set fragments) { - if (LOG.isDebugEnabled()) { - LOG.debug("Checked ledgers returned {} {}", rc, fragments); - } - if (rc == BKException.Code.OK) { - numFragments.set(fragments.size()); - } - checklatch.countDown(); - } - }); - checklatch.await(); - assertEquals("There should be no missing fragments", 0, numFragments.get()); - } - - @Test - public void testWaitForWritable() throws Exception { - final ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkc = new BookKeeper(conf); - - byte[] pwd = new byte[]{}; - try (LedgerHandle lh = bkc.createLedger(1, 1, 1, BookKeeper.DigestType.CRC32, pwd)) { - long entryId = lh.addEntry(this.entry); - - RoundRobinDistributionSchedule schedule = new RoundRobinDistributionSchedule(1, 1, 1); - DistributionSchedule.WriteSet writeSet = schedule.getWriteSet(entryId); - - int slowBookieIndex = writeSet.get(ThreadLocalRandom.current().nextInt(writeSet.size())); - List curEns = lh.getCurrentEnsemble(); - - // disable channel writable - setTargetChannelState(bkc, curEns.get(slowBookieIndex), 0, false); - - AtomicBoolean isWriteable = new AtomicBoolean(false); - final long timeout = 10000; - - // waitForWritable async - new Thread(() -> isWriteable.set(lh.waitForWritable(writeSet, 0, timeout))).start(); - - Awaitility.await().pollDelay(5, TimeUnit.SECONDS).untilAsserted(() -> assertFalse(isWriteable.get())); - - // enable channel writable - setTargetChannelState(bkc, curEns.get(slowBookieIndex), 0, true); - Awaitility.await().untilAsserted(() -> assertTrue(isWriteable.get())); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestAddEntryQuorumTimeout.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestAddEntryQuorumTimeout.java deleted file mode 100644 index 319134d95e4..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestAddEntryQuorumTimeout.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test a quorum timeout for add entry operations. - */ -public class TestAddEntryQuorumTimeout extends BookKeeperClusterTestCase implements AddCallback { - - private static final Logger logger = LoggerFactory.getLogger(TestAddEntryQuorumTimeout.class); - - final DigestType digestType; - final byte[] testPasswd = "".getBytes(); - - public TestAddEntryQuorumTimeout() { - super(3); - baseClientConf.setAddEntryTimeout(10); - baseClientConf.setAddEntryQuorumTimeout(1); - this.digestType = DigestType.CRC32; - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - } - - private static class SyncObj { - volatile int counter = 0; - volatile int rc = -1; - public SyncObj() { - counter = 0; - } - } - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - SyncObj x = (SyncObj) ctx; - synchronized (x) { - x.rc = rc; - x.counter++; - x.notify(); - } - } - - @Test - public void testBasicTimeout() throws Exception { - BookKeeperTestClient bkc = new BookKeeperTestClient(baseClientConf); - LedgerHandle lh = bkc.createLedger(3, 3, 3, digestType, testPasswd); - List curEns = lh.getCurrentEnsemble(); - byte[] data = "foobar".getBytes(); - lh.addEntry(data); - sleepBookie(curEns.get(0), 5).await(); - try { - lh.addEntry(data); - fail("should have thrown"); - } catch (BKException.BKAddEntryQuorumTimeoutException ex) { - } - } - - private void waitForSyncObj(SyncObj syncObj) throws Exception { - synchronized (syncObj) { - while (syncObj.counter < 1) { - logger.debug("Entries counter = " + syncObj.counter); - syncObj.wait(); - } - } - } - - @Test - public void testTimeoutWithPendingOps() throws Exception { - BookKeeperTestClient bkc = new BookKeeperTestClient(baseClientConf); - LedgerHandle lh = bkc.createLedger(3, 3, 3, digestType, testPasswd); - List curEns = lh.getCurrentEnsemble(); - byte[] data = "foobar".getBytes(); - - SyncObj syncObj1 = new SyncObj(); - SyncObj syncObj2 = new SyncObj(); - SyncObj syncObj3 = new SyncObj(); - - lh.addEntry(data); - sleepBookie(curEns.get(0), 5).await(); - lh.asyncAddEntry(data, this, syncObj1); - lh.asyncAddEntry(data, this, syncObj2); - lh.asyncAddEntry(data, this, syncObj3); - - waitForSyncObj(syncObj1); - assertEquals(BKException.Code.AddEntryQuorumTimeoutException, syncObj1.rc); - waitForSyncObj(syncObj2); - assertEquals(BKException.Code.AddEntryQuorumTimeoutException, syncObj2.rc); - waitForSyncObj(syncObj3); - assertEquals(BKException.Code.AddEntryQuorumTimeoutException, syncObj3.rc); - } - - @Test - public void testLedgerClosedAfterTimeout() throws Exception { - BookKeeperTestClient bkc = new BookKeeperTestClient(baseClientConf); - LedgerHandle lh = bkc.createLedger(3, 3, 3, digestType, testPasswd); - List curEns = lh.getCurrentEnsemble(); - byte[] data = "foobar".getBytes(); - CountDownLatch b0latch = sleepBookie(curEns.get(0), 5); - try { - lh.addEntry(data); - fail("should have thrown"); - } catch (BKException.BKAddEntryQuorumTimeoutException ex) { - } - b0latch.await(); - try { - lh.addEntry(data); - fail("should have thrown"); - } catch (BKException.BKLedgerClosedException ex) { - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBatchedRead.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBatchedRead.java deleted file mode 100644 index 1bb95ed0478..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBatchedRead.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerEntry; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit tests for batch reading. - */ -public class TestBatchedRead extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(TestBatchedRead.class); - - final DigestType digestType; - final byte[] passwd = "sequence-read".getBytes(); - - public TestBatchedRead() { - super(6); - baseClientConf.setUseV2WireProtocol(true); - this.digestType = DigestType.CRC32; - } - - long getLedgerToRead(int ensemble, int writeQuorum, int ackQuorum, int numEntries) - throws Exception { - LedgerHandle lh = bkc.createLedger(ensemble, writeQuorum, ackQuorum, digestType, passwd); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("" + i).getBytes()); - } - lh.close(); - return lh.getId(); - } - - BatchedReadOp createReadOp(LedgerHandle lh, long startEntry, int count) { - return new BatchedReadOp(lh, bkc.getClientCtx(), startEntry, count, 1024 * count, false); - } - - BatchedReadOp createRecoveryReadOp(LedgerHandle lh, long startEntry, int count) { - return new BatchedReadOp(lh, bkc.getClientCtx(), startEntry, count, 1024 * count, true); - } - - @Test - public void testNormalRead() throws Exception { - int numEntries = 10; - long id = getLedgerToRead(5, 5, 2, numEntries); - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - //read single entry - for (int i = 0; i < numEntries; i++) { - BatchedReadOp readOp = createReadOp(lh, i, 1); - readOp.submit(); - Iterator entries = readOp.future().get().iterator(); - assertTrue(entries.hasNext()); - LedgerEntry entry = entries.next(); - assertNotNull(entry); - assertEquals(i, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - assertFalse(entries.hasNext()); - } - - // read multiple entries - BatchedReadOp readOp = createReadOp(lh, 0, numEntries); - readOp.submit(); - Iterator iterator = readOp.future().get().iterator(); - - int numReads = 0; - while (iterator.hasNext()) { - LedgerEntry entry = iterator.next(); - assertNotNull(entry); - assertEquals(numReads, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - ++numReads; - } - assertEquals(numEntries, numReads); - lh.close(); - } - - @Test - public void testReadWhenEnsembleNotEqualWQ() throws Exception { - int numEntries = 10; - long id = getLedgerToRead(5, 2, 2, numEntries); - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - //read single entry - for (int i = 0; i < numEntries; i++) { - BatchedReadOp readOp = createReadOp(lh, i, 1); - readOp.submit(); - Iterator entries = readOp.future().get().iterator(); - assertTrue(entries.hasNext()); - LedgerEntry entry = entries.next(); - assertNotNull(entry); - assertEquals(i, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - assertFalse(entries.hasNext()); - } - - // read multiple entries, because the ensemble is not equals with write quorum, the return entries - // will less than max count. - for (int i = 0; i < numEntries; i++) { - BatchedReadOp readOp = createReadOp(lh, i, numEntries); - readOp.submit(); - Iterator entries = readOp.future().get().iterator(); - assertTrue(entries.hasNext()); - LedgerEntry entry = entries.next(); - assertNotNull(entry); - assertEquals(i, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - assertFalse(entries.hasNext()); - } - lh.close(); - } - - private static void expectFail(CompletableFuture future, int expectedRc) { - try { - result(future); - fail("Expect to fail"); - } catch (Exception e) { - assertTrue(e instanceof BKException); - BKException bke = (BKException) e; - assertEquals(expectedRc, bke.getCode()); - } - } - - @Test - public void testReadMissingEntries() throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 5, 2, numEntries); - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - // read single entry - BatchedReadOp readOp = createReadOp(lh, 10, 1); - readOp.submit(); - expectFail(readOp.future(), Code.NoSuchEntryException); - - // read multiple entries - readOp = createReadOp(lh, 8, 3); - readOp.submit(); - - int index = 8; - int numReads = 0; - Iterator iterator = readOp.future().get().iterator(); - while (iterator.hasNext()) { - LedgerEntry entry = iterator.next(); - assertNotNull(entry); - assertEquals(index, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - ++index; - ++numReads; - } - assertEquals(2, numReads); - lh.close(); - } - - @Test - public void testFailRecoveryReadMissingEntryImmediately() throws Exception { - int numEntries = 1; - - long id = getLedgerToRead(5, 5, 3, numEntries); - - ClientConfiguration newConf = new ClientConfiguration() - .setReadEntryTimeout(30000); - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper newBk = new BookKeeper(newConf); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = lh.getLedgerMetadata().getEnsembleAt(10); - CountDownLatch latch1 = new CountDownLatch(1); - CountDownLatch latch2 = new CountDownLatch(1); - // sleep two bookie - sleepBookie(ensemble.get(0), latch1); - sleepBookie(ensemble.get(1), latch2); - - BatchedReadOp readOp = createRecoveryReadOp(lh, 10, 1); - readOp.submit(); - // would fail immediately if found missing entries don't cover ack quorum - expectFail(readOp.future(), Code.NoSuchEntryException); - latch1.countDown(); - latch2.countDown(); - - lh.close(); - newBk.close(); - } - - @Test - public void testReadWithFailedBookies() throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 3, 3, numEntries); - - ClientConfiguration newConf = new ClientConfiguration() - .setReadEntryTimeout(30000); - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper newBk = new BookKeeper(newConf); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = lh.getLedgerMetadata().getEnsembleAt(5); - // kill two bookies - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - - // read multiple entries, because the ensemble is not equals with write quorum, the return entries - // will less than max count. - int numReads = 0; - for (int i = 0; i < numEntries;) { - BatchedReadOp readOp = createReadOp(lh, i, numEntries); - readOp.submit(); - Iterator entries = readOp.future().get().iterator(); - if (!entries.hasNext()) { - i++; - continue; - } - while (entries.hasNext()) { - LedgerEntry entry = entries.next(); - assertNotNull(entry); - assertEquals(i, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - i++; - numReads++; - } - } - assertEquals(10, numReads); - lh.close(); - newBk.close(); - } - - @Test - public void testReadFailureWithFailedBookies() throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 3, 3, numEntries); - - ClientConfiguration newConf = new ClientConfiguration() - .setReadEntryTimeout(30000); - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper newBk = new BookKeeper(newConf); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = lh.getLedgerMetadata().getEnsembleAt(5); - // kill two bookies - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - killBookie(ensemble.get(2)); - - // read multiple entries - BatchedReadOp readOp = createReadOp(lh, 0, numEntries); - readOp.submit(); - expectFail(readOp.future(), Code.BookieHandleNotAvailableException); - - lh.close(); - newBk.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieHealthCheck.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieHealthCheck.java deleted file mode 100644 index 0fee2aa1677..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieHealthCheck.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.client; - -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the BookieHealthCheck. - */ -public class TestBookieHealthCheck extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestBookieHealthCheck.class); - - public TestBookieHealthCheck() { - super(4); - baseClientConf.setAddEntryTimeout(1); - baseClientConf.enableBookieHealthCheck(); - baseClientConf.setBookieHealthCheckInterval(1, TimeUnit.SECONDS); - baseClientConf.setBookieErrorThresholdPerInterval(1); - baseClientConf.setBookieQuarantineTime(5, TimeUnit.SECONDS); - } - - @Test - public void testBkQuarantine() throws Exception { - LedgerHandle lh = bkc.createLedger(2, 2, 2, BookKeeper.DigestType.CRC32, new byte[] {}); - - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - byte[] msg = ("msg-" + i).getBytes(); - lh.addEntry(msg); - } - - BookieId bookieToQuarantine = lh.getLedgerMetadata().getEnsembleAt(numEntries).get(0); - sleepBookie(bookieToQuarantine, baseClientConf.getAddEntryTimeout() * 2).await(); - - byte[] tempMsg = "temp-msg".getBytes(); - lh.asyncAddEntry(tempMsg, new AddCallback() { - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - // no-op - } - }, null); - - // make sure the add entry timeouts - Thread.sleep(baseClientConf.getAddEntryTimeout() * 2 * 1000); - - // make sure the health check runs once after the timeout - Thread.sleep(baseClientConf.getBookieHealthCheckIntervalSeconds() * 2 * 1000); - - // the bookie watcher should contain the bookieToQuarantine in the quarantine set - Assert.assertTrue(bkc.bookieWatcher.quarantinedBookies.asMap().containsKey(bookieToQuarantine)); - - // the bookie to be left out of the ensemble should always be the quarantined bookie - LedgerHandle lh1 = bkc.createLedger(2, 2, 2, BookKeeper.DigestType.CRC32, new byte[] {}); - LedgerHandle lh2 = bkc.createLedger(3, 3, 3, BookKeeper.DigestType.CRC32, new byte[] {}); - Assert.assertFalse(lh1.getLedgerMetadata().getEnsembleAt(0).contains(bookieToQuarantine)); - Assert.assertFalse(lh2.getLedgerMetadata().getEnsembleAt(0).contains(bookieToQuarantine)); - - // the quarantined bookie can still be in the ensemble if we do not have enough healthy bookies - LedgerHandle lh3 = bkc.createLedger(4, 4, 4, BookKeeper.DigestType.CRC32, new byte[] {}); - Assert.assertTrue(lh3.getLedgerMetadata().getEnsembleAt(0).contains(bookieToQuarantine)); - - // make sure faulty bookie is out of quarantine - Thread.sleep(baseClientConf.getBookieQuarantineTimeSeconds() * 1000); - - // the bookie should not be quarantined anymore - Assert.assertFalse(bkc.bookieWatcher.quarantinedBookies.asMap().containsKey(bookieToQuarantine)); - } - - @Test - public void testNoQuarantineOnBkRestart() throws Exception { - final LedgerHandle lh = bkc.createLedger(2, 2, 2, BookKeeper.DigestType.CRC32, new byte[] {}); - final int numEntries = 20; - BookieId bookieToRestart = lh.getLedgerMetadata().getEnsembleAt(0).get(0); - - // we add entries on a separate thread so that we can restart a bookie on the current thread - Thread addEntryThread = new Thread() { - public void run() { - for (int i = 0; i < numEntries; i++) { - byte[] msg = ("msg-" + i).getBytes(); - try { - lh.addEntry(msg); - // we add sufficient sleep to make sure all entries are not added before we restart the bookie - Thread.sleep(100); - } catch (Exception e) { - LOG.error("Error sending msg"); - } - } - } - }; - addEntryThread.start(); - restartBookie(bookieToRestart); - - // make sure the health check runs once - Thread.sleep(baseClientConf.getBookieHealthCheckIntervalSeconds() * 2 * 1000); - - // the bookie watcher should not contain the bookieToRestart in the quarantine set - Assert.assertFalse(bkc.bookieWatcher.quarantinedBookies.asMap().containsKey(bookieToRestart)); - } - - @Test - public void testNoQuarantineOnExpectedBkErrors() throws Exception { - final LedgerHandle lh = bkc.createLedger(2, 2, 2, BookKeeper.DigestType.CRC32, new byte[] {}); - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - byte[] msg = ("msg-" + i).getBytes(); - lh.addEntry(msg); - } - BookieId bookie1 = lh.getLedgerMetadata().getEnsembleAt(0).get(0); - BookieId bookie2 = lh.getLedgerMetadata().getEnsembleAt(0).get(1); - try { - // we read an entry that is not added - lh.readEntries(10, 10); - } catch (BKException e) { - // ok - } - - // make sure the health check runs once - Thread.sleep(baseClientConf.getBookieHealthCheckIntervalSeconds() * 2 * 1000); - - // the bookie watcher should not contain the bookieToRestart in the quarantine set - Assert.assertFalse(bkc.bookieWatcher.quarantinedBookies.asMap().containsKey(bookie1)); - Assert.assertFalse(bkc.bookieWatcher.quarantinedBookies.asMap().containsKey(bookie2)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieWatcher.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieWatcher.java deleted file mode 100644 index 6c2f004826c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieWatcher.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import lombok.Cleanup; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.ZooKeeper; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test a bookie watcher. - */ -public class TestBookieWatcher extends BookKeeperClusterTestCase { - - public TestBookieWatcher() { - super(2); - } - - private void expireZooKeeperSession(ZooKeeper zk, int timeout) - throws IOException, InterruptedException, KeeperException { - final CountDownLatch latch = new CountDownLatch(1); - ZooKeeper newZk = new ZooKeeper(zkUtil.getZooKeeperConnectString(), timeout, - new Watcher() { - - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.None && event.getState() == KeeperState.SyncConnected) { - latch.countDown(); - } - } - - }, zk.getSessionId(), zk.getSessionPasswd()); - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - throw KeeperException.create(KeeperException.Code.CONNECTIONLOSS); - } - newZk.close(); - } - - /** - * Test to validate behavior of the isBookieUnavailable method. - * Because the method relies on getBookies and getReadOnlyBookies, - * these methods are essentially tested here as well. - * - * @throws Exception - */ - @Test - public void testBookieWatcherIsBookieUnavailable() throws Exception { - BookieWatcher bookieWatcher = bkc.getBookieWatcher(); - - Set writableBookies1 = bookieWatcher.getBookies(); - Set readonlyBookies1 = bookieWatcher.getReadOnlyBookies(); - - Assert.assertEquals("There should be writable bookies initially.", 2, writableBookies1.size()); - Assert.assertEquals("There should be no read only bookies initially.", - Collections.emptySet(), readonlyBookies1); - - BookieId bookieId0 = getBookie(0); - BookieId bookieId1 = getBookie(1); - - boolean isUnavailable1 = bookieWatcher.isBookieUnavailable(bookieId0); - Assert.assertFalse("The bookie should not be unavailable.", isUnavailable1); - - // Next, set to read only, which is still available - setBookieToReadOnly(bookieId0); - - Set writableBookies2 = bookieWatcher.getBookies(); - Set readonlyBookies2 = bookieWatcher.getReadOnlyBookies(); - - Assert.assertEquals("There should be one writable bookie.", - Collections.singleton(bookieId1), writableBookies2); - Assert.assertEquals("There should be one read only bookie.", - Collections.singleton(bookieId0), readonlyBookies2); - - boolean isUnavailable2 = bookieWatcher.isBookieUnavailable(bookieId0); - Assert.assertFalse("The bookie should not be unavailable.", isUnavailable2); - - // Next, kill it, which should make it unavailable - killBookieAndWaitForZK(0); - - Set writableBookies3 = bookieWatcher.getBookies(); - Set readonlyBookies3 = bookieWatcher.getReadOnlyBookies(); - - Assert.assertEquals("There should be one writable bookie.", - Collections.singleton(bookieId1), writableBookies3); - Assert.assertEquals("There should be no read only bookies.", Collections.emptySet(), readonlyBookies3); - - boolean isUnavailable3 = bookieWatcher.isBookieUnavailable(bookieId0); - Assert.assertTrue("The bookie should be unavailable.", isUnavailable3); - } - - @Test - public void testBookieWatcherSurviveWhenSessionExpired() throws Exception { - final int timeout = 2000; - try (ZooKeeperClient zk = ZooKeeperClient.newBuilder() - .connectString(zkUtil.getZooKeeperConnectString()) - .sessionTimeoutMs(timeout) - .build()) { - runBookieWatcherWhenSessionExpired(zk, timeout, true); - } - } - - @Test - public void testBookieWatcherDieWhenSessionExpired() throws Exception { - final int timeout = 2000; - final CountDownLatch connectLatch = new CountDownLatch(1); - - @Cleanup - ZooKeeper zk = new ZooKeeper(zkUtil.getZooKeeperConnectString(), timeout, new Watcher() { - @Override - public void process(WatchedEvent watchedEvent) { - if (EventType.None == watchedEvent.getType() - && KeeperState.SyncConnected == watchedEvent.getState()) { - connectLatch.countDown(); - } - } - }); - - connectLatch.await(); - runBookieWatcherWhenSessionExpired(zk, timeout, false); - } - - private void runBookieWatcherWhenSessionExpired(ZooKeeper zk, int timeout, boolean reconnectable) - throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri); - - try (BookKeeperTestClient bkc = new BookKeeperTestClient(conf, zk)) { - - LedgerHandle lh; - try { - lh = bkc.createLedger(3, 2, 2, BookKeeper.DigestType.CRC32, new byte[]{}); - fail("Should fail to create ledger due to not enough bookies."); - } catch (BKException bke) { - // expected - } - - // make zookeeper session expired - expireZooKeeperSession(bkc.getZkHandle(), timeout); - TimeUnit.MILLISECONDS.sleep(3 * timeout); - - // start four new bookies - for (int i = 0; i < 2; i++) { - startNewBookie(); - } - - // wait for bookie watcher backoff time. - TimeUnit.SECONDS.sleep(1); - - // should success to detect newly added bookies - try { - lh = bkc.createLedger(3, 2, 2, BookKeeper.DigestType.CRC32, new byte[]{}); - lh.close(); - if (!reconnectable) { - fail("Should fail to create ledger due to bookie watcher could not survive after session expire."); - } - } catch (BKException bke) { - if (reconnectable) { - fail("Should not fail to create ledger due to bookie watcher could survive after session expire."); - } - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java deleted file mode 100644 index 581d46905fe..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.NEW_ENSEMBLE_TIME; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.REPLACE_BOOKIE_TIME; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.WATCHER_SCOPE; -import static org.apache.bookkeeper.client.BookKeeperClientStats.CLIENT_SCOPE; -import static org.apache.bookkeeper.client.BookKeeperClientStats.LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.TestUtils; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test a delayed ensemble change. - */ -public class TestDelayEnsembleChange extends BookKeeperClusterTestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestDelayEnsembleChange.class); - - final DigestType digestType; - final byte[] testPasswd = "".getBytes(); - - public TestDelayEnsembleChange() { - super(5); - this.digestType = DigestType.CRC32; - } - - @Before - @Override - public void setUp() throws Exception { - baseClientConf.setDelayEnsembleChange(true); - super.setUp(); - } - - private static class VerificationCallback implements ReadEntryCallback { - final CountDownLatch latch; - final AtomicLong numSuccess; - final AtomicLong numMissing; - final AtomicLong numFailure; - - VerificationCallback(int numRequests) { - latch = new CountDownLatch(numRequests); - numSuccess = new AtomicLong(0L); - numMissing = new AtomicLong(0L); - numFailure = new AtomicLong(0L); - } - - @Override - public void readEntryComplete(int rc, long ledgerId, long entryId, ByteBuf buffer, Object ctx) { - if (rc == BKException.Code.OK) { - numSuccess.incrementAndGet(); - } else if (rc == BKException.Code.NoSuchEntryException - || rc == BKException.Code.NoSuchLedgerExistsException) { - logger.error("Missed entry({}, {}) from host {}.", ledgerId, entryId, ctx); - numMissing.incrementAndGet(); - } else { - logger.error("Failed to get entry({}, {}) from host {} : {}", - ledgerId, entryId, ctx, rc); - numFailure.incrementAndGet(); - } - latch.countDown(); - } - } - - private void verifyEntries(LedgerHandle lh, long startEntry, long untilEntry, - long expectedSuccess, long expectedMissing) throws Exception { - LedgerMetadata md = lh.getLedgerMetadata(); - - for (long eid = startEntry; eid < untilEntry; eid++) { - List addresses = md.getEnsembleAt(eid); - VerificationCallback callback = new VerificationCallback(addresses.size()); - for (BookieId addr : addresses) { - bkc.getBookieClient().readEntry(addr, lh.getId(), eid, - callback, addr, 0, null); - } - callback.latch.await(); - assertEquals(expectedSuccess, callback.numSuccess.get()); - assertEquals(expectedMissing, callback.numMissing.get()); - assertEquals(0, callback.numFailure.get()); - } - } - - private void verifyEntriesRange(LedgerHandle lh, long startEntry, long untilEntry, - long expectedSuccess, long expectedMissing) throws Exception { - LedgerMetadata md = lh.getLedgerMetadata(); - - for (long eid = startEntry; eid < untilEntry; eid++) { - List addresses = md.getEnsembleAt(eid); - VerificationCallback callback = new VerificationCallback(addresses.size()); - for (BookieId addr : addresses) { - bkc.getBookieClient().readEntry(addr, lh.getId(), eid, - callback, addr, 0, null); - } - callback.latch.await(); - assertTrue(expectedSuccess >= callback.numSuccess.get()); - assertTrue(expectedMissing <= callback.numMissing.get()); - assertEquals(0, callback.numFailure.get()); - } - } - - @Test - public void testNotChangeEnsembleIfNotBrokenAckQuorum() throws Exception { - LedgerHandle lh = bkc.createLedger(5, 5, 3, digestType, testPasswd); - - byte[] data = "foobar".getBytes(); - - int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - - // kill two bookies, but we still have 3 bookies for the ack quorum. - ServerConfiguration conf0 = killBookie(lh.getCurrentEnsemble().get(0)); - ServerConfiguration conf1 = killBookie(lh.getCurrentEnsemble().get(1)); - - for (int i = numEntries; i < 2 * numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("There should be no ensemble change if delaying ensemble change is enabled.", - 1, lh.getLedgerMetadata().getAllEnsembles().size()); - - startAndAddBookie(conf0); - startAndAddBookie(conf1); - - for (int i = 2 * numEntries; i < 3 * numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("There should be no ensemble change if delaying ensemble change is enabled.", - 1, lh.getLedgerMetadata().getAllEnsembles().size()); - - // check entries - verifyEntries(lh, 0, numEntries, 5, 0); - verifyEntries(lh, numEntries, 2 * numEntries, 3, 2); - verifyEntries(lh, 2 * numEntries, 3 * numEntries, 5, 0); - } - - @Test - public void testChangeEnsembleIfBrokenAckQuorum() throws Exception { - startNewBookie(); - startNewBookie(); - startNewBookie(); - - bkc.getTestStatsProvider().clear(); - LedgerHandle lh = bkc.createLedger(5, 5, 3, digestType, testPasswd); - - byte[] data = "foobar".getBytes(); - - int numEntries = 5; - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - - for (BookieId addr : lh.getLedgerMetadata().getAllEnsembles().get(0L)) { - StringBuilder nameBuilder = new StringBuilder(CLIENT_SCOPE); - nameBuilder.append('.'). - append("bookie_"). - append(TestUtils.buildStatsCounterPathFromBookieID(addr)). - append('.'). - append(LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION); - assertTrue( - LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION + " should be > 0 for " + addr, - bkc.getTestStatsProvider().getCounter(nameBuilder.toString()) - .get() > 0); - } - assertTrue( - "Stats should have captured a new ensemble", - bkc.getTestStatsProvider().getOpStatsLogger( - CLIENT_SCOPE + "." + WATCHER_SCOPE + "." + NEW_ENSEMBLE_TIME) - .getSuccessCount() > 0); - assertTrue( - "Stats should not have captured an ensemble change", - bkc.getTestStatsProvider().getOpStatsLogger( - CLIENT_SCOPE + "." + WATCHER_SCOPE + "." + REPLACE_BOOKIE_TIME) - .getSuccessCount() == 0); - - logger.info("Kill bookie 0 and write {} entries.", numEntries); - - // kill two bookies, but we still have 3 bookies for the ack quorum. - ServerConfiguration conf0 = killBookie(lh.getCurrentEnsemble().get(0)); - - for (int i = numEntries; i < 2 * numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("There should be no ensemble change if delaying ensemble change is enabled.", - 1, lh.getLedgerMetadata().getAllEnsembles().size()); - assertTrue( - "Stats should not have captured an ensemble change", - bkc.getTestStatsProvider().getOpStatsLogger( - CLIENT_SCOPE + "." + WATCHER_SCOPE + "." + REPLACE_BOOKIE_TIME) - .getSuccessCount() == 0); - - logger.info("Kill bookie 1 and write another {} entries.", numEntries); - - ServerConfiguration conf1 = killBookie(lh.getCurrentEnsemble().get(1)); - - for (int i = 2 * numEntries; i < 3 * numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("There should be no ensemble change if delaying ensemble change is enabled.", - 1, lh.getLedgerMetadata().getAllEnsembles().size()); - - logger.info("Kill bookie 2 and write another {} entries.", numEntries); - - ServerConfiguration conf2 = killBookie(lh.getCurrentEnsemble().get(2)); - - for (int i = 3 * numEntries; i < 4 * numEntries; i++) { - lh.addEntry(data); - } - - // ensemble change should kick in - assertEquals("There should be ensemble change if ack quorum couldn't be formed.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - assertTrue( - "Stats should have captured an ensemble change", - bkc.getTestStatsProvider().getOpStatsLogger( - CLIENT_SCOPE + "." + WATCHER_SCOPE + "." + REPLACE_BOOKIE_TIME) - .getSuccessCount() > 0); - - List firstFragment = lh.getLedgerMetadata().getEnsembleAt(0); - List secondFragment = lh.getLedgerMetadata().getEnsembleAt(3 * numEntries); - assertFalse(firstFragment.get(0).equals(secondFragment.get(0))); - assertFalse(firstFragment.get(1).equals(secondFragment.get(1))); - assertFalse(firstFragment.get(2).equals(secondFragment.get(2))); - assertEquals(firstFragment.get(3), secondFragment.get(3)); - assertEquals(firstFragment.get(4), secondFragment.get(4)); - - startAndAddBookie(conf0); - startAndAddBookie(conf1); - startAndAddBookie(conf2); - - for (int i = 4 * numEntries; i < 5 * numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("There should be no ensemble change if delaying ensemble change is enabled.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - - // check entries - verifyEntries(lh, 0, numEntries, 5, 0); - verifyEntries(lh, numEntries, 2 * numEntries, 4, 1); - verifyEntries(lh, 2 * numEntries, 3 * numEntries, 3, 2); - verifyEntries(lh, 3 * numEntries, 4 * numEntries, 5, 0); - verifyEntries(lh, 4 * numEntries, 5 * numEntries, 5, 0); - } - - @Test - public void testEnsembleChangeWithNotEnoughBookies() throws Exception { - startNewBookie(); - - LedgerHandle lh = bkc.createLedger(5, 5, 3, digestType, testPasswd); - - byte[] data = "foobar".getBytes(); - - int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - - logger.info("Killed 3 bookies and add {} more entries : {}", numEntries, lh.getLedgerMetadata()); - - // kill three bookies, but we only have 2 new bookies for ensemble change. - ServerConfiguration conf0 = killBookie(lh.getCurrentEnsemble().get(0)); - ServerConfiguration conf1 = killBookie(lh.getCurrentEnsemble().get(1)); - ServerConfiguration conf2 = killBookie(lh.getCurrentEnsemble().get(2)); - - for (int i = numEntries; i < 2 * numEntries; i++) { - lh.addEntry(data); - } - - logger.info("Ledger metadata after killed bookies : {}", lh.getLedgerMetadata()); - - // ensure there is ensemble changed - assertEquals("There should be ensemble change if ack quorum is broken.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - - startAndAddBookie(conf0); - startAndAddBookie(conf1); - startAndAddBookie(conf2); - - for (int i = 2 * numEntries; i < 3 * numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("There should be no ensemble change after adding failed bookies back.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - - // check entries - verifyEntries(lh, 0, numEntries, 5, 0); - verifyEntries(lh, numEntries, 2 * numEntries, 3, 2); - verifyEntries(lh, 2 * numEntries, 3 * numEntries, 5, 0); - } - - @Test - public void testEnsembleChangeWithMoreBookieFailures() throws Exception { - for (int i = 0; i < 5; i++) { - startNewBookie(); - } - - LedgerHandle lh = bkc.createLedger(5, 5, 3, digestType, testPasswd); - - byte[] data = "foobar".getBytes(); - - int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - logger.info("Add entry {}", i); - lh.addEntry(data); - } - - logger.info("Killed 5 bookies and add {} more entries : {}", numEntries, lh.getLedgerMetadata()); - - // kill 5 bookies to introduce more bookie failure - List confs = new ArrayList(5); - for (int i = 0; i < 5; i++) { - confs.add(killBookie(lh.getCurrentEnsemble().get(i))); - } - - for (int i = numEntries; i < 2 * numEntries; i++) { - logger.info("Add entry {}", i); - lh.addEntry(data); - } - - logger.info("Ledger metadata after killed bookies : {}", lh.getLedgerMetadata()); - - // ensure there is no ensemble changed - assertEquals("There should be ensemble change if breaking ack quorum.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - - for (ServerConfiguration conf : confs) { - startAndAddBookie(conf); - } - - for (int i = 2 * numEntries; i < 3 * numEntries; i++) { - logger.info("Add entry {}", i); - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("There should not be ensemble changed if delaying ensemble change is enabled.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - - // check entries - verifyEntries(lh, 0, numEntries, 5, 0); - verifyEntriesRange(lh, numEntries, 2 * numEntries, 5, 0); - verifyEntries(lh, 2 * numEntries, 3 * numEntries, 5, 0); - } - - @Test - public void testChangeEnsembleIfBookieReadOnly() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, 2, digestType, testPasswd); - - byte[] data = "foobar".getBytes(); - - int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - - // kill two bookies, but we still have 3 bookies for the ack quorum. - setBookieToReadOnly(lh.getCurrentEnsemble().get(0)); - - for (int i = numEntries; i < 2 * numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("The ensemble should change when a bookie is readonly even if we delay ensemble change.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - - } - - @Test - public void testChangeEnsembleSecondBookieReadOnly() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, 2, digestType, testPasswd); - - byte[] data = "foobar".getBytes(); - - int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - - BookieId failedBookie = lh.getCurrentEnsemble().get(0); - BookieId readOnlyBookie = lh.getCurrentEnsemble().get(1); - ServerConfiguration conf0 = killBookie(failedBookie); - - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - - assertEquals("There should be ensemble change if delaying ensemble change is enabled.", - 1, lh.getLedgerMetadata().getAllEnsembles().size()); - - // kill two bookies, but we still have 3 bookies for the ack quorum. - setBookieToReadOnly(readOnlyBookie); - - for (int i = 0; i < numEntries; i++) { - lh.addEntry(data); - } - - // ensure there is no ensemble changed - assertEquals("The ensemble should change when a bookie is readonly even if we delay ensemble change.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - assertEquals(3, lh.getCurrentEnsemble().size()); - assertFalse(lh.getCurrentEnsemble().contains(failedBookie)); - assertFalse(lh.getCurrentEnsemble().contains(readOnlyBookie)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDisableEnsembleChange.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDisableEnsembleChange.java deleted file mode 100644 index 286e8152e24..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDisableEnsembleChange.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.util.BookKeeperConstants.FEATURE_DISABLE_ENSEMBLE_CHANGE; -import static org.apache.bookkeeper.util.TestUtils.assertEventuallyTrue; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.common.util.concurrent.RateLimiter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.feature.SettableFeature; -import org.apache.bookkeeper.feature.SettableFeatureProvider; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Case on Disabling Ensemble Change Feature. - */ -public class TestDisableEnsembleChange extends BookKeeperClusterTestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestDisableEnsembleChange.class); - - public TestDisableEnsembleChange() { - super(4); - } - - @Test - public void testDisableEnsembleChange() throws Exception { - disableEnsembleChangeTest(true); - } - - @Test - public void testDisableEnsembleChangeNotEnoughBookies() throws Exception { - disableEnsembleChangeTest(false); - } - - void disableEnsembleChangeTest(boolean startNewBookie) throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri) - .setDelayEnsembleChange(false) - .setDisableEnsembleChangeFeatureName(FEATURE_DISABLE_ENSEMBLE_CHANGE); - - SettableFeatureProvider featureProvider = new SettableFeatureProvider("test", 0); - BookKeeper bkc = BookKeeper.forConfig(conf) - .featureProvider(featureProvider) - .build(); - - SettableFeature disableEnsembleChangeFeature = featureProvider.getFeature(FEATURE_DISABLE_ENSEMBLE_CHANGE); - disableEnsembleChangeFeature.set(true); - - final byte[] password = new byte[0]; - final LedgerHandle lh = bkc.createLedger(4, 3, 2, BookKeeper.DigestType.CRC32, password); - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failTest = new AtomicBoolean(false); - final byte[] entry = "test-disable-ensemble-change".getBytes(UTF_8); - - assertEquals(1, lh.getLedgerMetadata().getAllEnsembles().size()); - ArrayList ensembleBeforeFailure = - new ArrayList<>(lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next().getValue()); - - final RateLimiter rateLimiter = RateLimiter.create(10); - - Thread addThread = new Thread() { - @Override - public void run() { - try { - while (!finished.get()) { - rateLimiter.acquire(); - lh.addEntry(entry); - } - } catch (Exception e) { - logger.error("Exception on adding entry : ", e); - failTest.set(true); - } - } - }; - addThread.start(); - Thread.sleep(2000); - killBookie(0); - Thread.sleep(2000); - finished.set(true); - addThread.join(); - - assertFalse("Should not fail adding entries facing one bookie failure when disable ensemble change", - failTest.get()); - - // check the ensemble after failure - assertEquals("No new ensemble should be added when disable ensemble change.", - 1, lh.getLedgerMetadata().getAllEnsembles().size()); - ArrayList ensembleAfterFailure = - new ArrayList<>(lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next().getValue()); - assertArrayEquals(ensembleBeforeFailure.toArray(new BookieId[ensembleBeforeFailure.size()]), - ensembleAfterFailure.toArray(new BookieId[ensembleAfterFailure.size()])); - - // enable ensemble change - disableEnsembleChangeFeature.set(false); - if (startNewBookie) { - startNewBookie(); - } - - // reset add thread - finished.set(false); - final CountDownLatch failLatch = new CountDownLatch(1); - - addThread = new Thread() { - @Override - public void run() { - try { - while (!finished.get()) { - lh.addEntry(entry); - } - } catch (Exception e) { - logger.error("Exception on adding entry : ", e); - failLatch.countDown(); - failTest.set(true); - } - } - }; - addThread.start(); - failLatch.await(4000, TimeUnit.MILLISECONDS); - finished.set(true); - addThread.join(); - - if (startNewBookie) { - assertFalse("Should not fail adding entries when enable ensemble change again.", - failTest.get()); - assertFalse("Ledger should be closed when enable ensemble change again.", - lh.getLedgerMetadata().isClosed()); - assertEquals("New ensemble should be added when enable ensemble change again.", - 2, lh.getLedgerMetadata().getAllEnsembles().size()); - } else { - assertTrue("Should fail adding entries when enable ensemble change again.", - failTest.get()); - // The ledger close occurs in the background, so assert that it happens eventually - assertEventuallyTrue("Ledger should be closed when enable ensemble change again.", - () -> lh.getLedgerMetadata().isClosed()); - } - } - - @Test - public void testRetryFailureBookie() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(metadataServiceUri) - .setDelayEnsembleChange(false) - .setDisableEnsembleChangeFeatureName(FEATURE_DISABLE_ENSEMBLE_CHANGE); - - SettableFeatureProvider featureProvider = new SettableFeatureProvider("test", 0); - BookKeeper bkc = BookKeeper.forConfig(conf) - .featureProvider(featureProvider) - .build(); - - SettableFeature disableEnsembleChangeFeature = featureProvider.getFeature(FEATURE_DISABLE_ENSEMBLE_CHANGE); - disableEnsembleChangeFeature.set(true); - - LedgerHandle lh = bkc.createLedger(4, 4, 4, BookKeeper.DigestType.CRC32, new byte[] {}); - byte[] entry = "testRetryFailureBookie".getBytes(); - for (int i = 0; i < 10; i++) { - lh.addEntry(entry); - } - // kill a bookie - ServerConfiguration killedConf = killBookie(0); - - final AtomicInteger res = new AtomicInteger(0xdeadbeef); - final CountDownLatch addLatch = new CountDownLatch(1); - AsyncCallback.AddCallback cb = new AsyncCallback.AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - logger.info("Add entry {} completed : rc {}.", entryId, rc); - res.set(rc); - addLatch.countDown(); - } - }; - lh.asyncAddEntry(entry, cb, null); - assertFalse("Add entry operation should not complete.", - addLatch.await(1000, TimeUnit.MILLISECONDS)); - assertEquals(res.get(), 0xdeadbeef); - // start the original bookie - startAndAddBookie(killedConf); - assertTrue("Add entry operation should complete at this point.", - addLatch.await(10000, TimeUnit.MILLISECONDS)); - assertEquals(res.get(), BKException.Code.OK); - } - - @Test - public void testRetrySlowBookie() throws Exception { - final int readTimeout = 2; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setReadEntryTimeout(readTimeout) - .setAddEntryTimeout(readTimeout) - .setDelayEnsembleChange(false) - .setDisableEnsembleChangeFeatureName(FEATURE_DISABLE_ENSEMBLE_CHANGE) - .setMetadataServiceUri(metadataServiceUri); - - SettableFeatureProvider featureProvider = new SettableFeatureProvider("test", 0); - BookKeeper bkc = BookKeeper.forConfig(conf) - .featureProvider(featureProvider) - .build(); - - SettableFeature disableEnsembleChangeFeature = featureProvider.getFeature(FEATURE_DISABLE_ENSEMBLE_CHANGE); - disableEnsembleChangeFeature.set(true); - - LedgerHandle lh = bkc.createLedger(4, 4, 4, BookKeeper.DigestType.CRC32, new byte[] {}); - byte[] entry = "testRetryFailureBookie".getBytes(); - for (int i = 0; i < 10; i++) { - lh.addEntry(entry); - } - - List curEns = lh.getCurrentEnsemble(); - - final CountDownLatch wakeupLatch = new CountDownLatch(1); - final CountDownLatch suspendLatch = new CountDownLatch(1); - sleepBookie(curEns.get(2), wakeupLatch, suspendLatch); - - suspendLatch.await(); - - final AtomicInteger res = new AtomicInteger(0xdeadbeef); - final CountDownLatch addLatch = new CountDownLatch(1); - AsyncCallback.AddCallback cb = new AsyncCallback.AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - logger.info("Add entry {} completed : rc {}.", entryId, rc); - res.set(rc); - addLatch.countDown(); - } - }; - lh.asyncAddEntry(entry, cb, null); - assertFalse("Add entry operation should not complete.", - addLatch.await(1000, TimeUnit.MILLISECONDS)); - assertEquals(res.get(), 0xdeadbeef); - // wait until read timeout - assertFalse("Add entry operation should not complete even timeout.", - addLatch.await(readTimeout, TimeUnit.SECONDS)); - assertEquals(res.get(), 0xdeadbeef); - // wait one more read timeout, to ensure we resend multiple retries - // to ensure it works correctly - assertFalse("Add entry operation should not complete even timeout.", - addLatch.await(readTimeout, TimeUnit.SECONDS)); - assertEquals(res.get(), 0xdeadbeef); - // wakeup the sleep bookie - wakeupLatch.countDown(); - assertTrue("Add entry operation should complete at this point.", - addLatch.await(10000, TimeUnit.MILLISECONDS)); - assertEquals(res.get(), BKException.Code.OK); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestFencing.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestFencing.java deleted file mode 100644 index 34751525aa6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestFencing.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This unit test tests ledger fencing. - * - */ -public class TestFencing extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestFencing.class); - - private final DigestType digestType; - - public TestFencing() { - super(10); - this.digestType = DigestType.CRC32; - } - - /** - * Basic fencing test. Create ledger, write to it, - * open ledger, write again (should fail). - */ - @Test - public void testBasicFencing() throws Exception { - /* - * Create ledger. - */ - LedgerHandle writelh = null; - writelh = bkc.createLedger(digestType, "password".getBytes()); - - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < 10; i++) { - writelh.addEntry(tmp.getBytes()); - } - - /* - * Try to open ledger. - */ - LedgerHandle readlh = bkc.openLedger(writelh.getId(), digestType, "password".getBytes()); - // should have triggered recovery and fencing - - try { - writelh.addEntry(tmp.getBytes()); - LOG.error("Should have thrown an exception"); - fail("Should have thrown an exception when trying to write"); - } catch (BKException.BKLedgerFencedException e) { - // correct behaviour - } - - /* - * Check if has recovered properly. - */ - assertTrue("Has not recovered correctly: " + readlh.getLastAddConfirmed() - + " original " + writelh.getLastAddConfirmed(), - readlh.getLastAddConfirmed() == writelh.getLastAddConfirmed()); - } - - private static int threadCount = 0; - - class LedgerOpenThread extends Thread { - private final long ledgerId; - private long lastConfirmedEntry = 0; - - - private final int tid; - private final DigestType digestType; - private final CyclicBarrier barrier; - - LedgerOpenThread (int tid, DigestType digestType, long ledgerId, CyclicBarrier barrier) - throws Exception { - super("TestFencing-LedgerOpenThread-" + threadCount++); - this.tid = tid; - this.ledgerId = ledgerId; - this.digestType = digestType; - this.barrier = barrier; - } - - @Override - public void run() { - LOG.info("Thread {} started.", tid); - LedgerHandle lh = null; - BookKeeper bk = null; - try { - barrier.await(); - while (true) { - try { - bk = new BookKeeper(new ClientConfiguration(baseClientConf), bkc.getZkHandle()); - - lh = bk.openLedger(ledgerId, - digestType, "".getBytes()); - lastConfirmedEntry = lh.getLastAddConfirmed(); - lh.close(); - break; - } catch (BKException.BKMetadataVersionException zke) { - LOG.info("Contention with someone else recovering"); - } catch (BKException.BKLedgerRecoveryException bkre) { - LOG.info("Contention with someone else recovering"); - } finally { - if (lh != null) { - lh.close(); - } - if (bk != null) { - bk.close(); - bk = null; - } - } - } - } catch (Exception e) { - // just exit, test should spot bad last add confirmed - LOG.error("Exception occurred ", e); - } - LOG.info("Thread {} exiting, lastConfirmedEntry = {}", tid, lastConfirmedEntry); - } - - long getLastConfirmedEntry() { - return lastConfirmedEntry; - } - } - - /** - * Try to open a ledger many times in parallel. - * All opens should result in a ledger with an equals number of - * entries. - */ - @Test - public void testManyOpenParallel() throws Exception { - /* - * Create ledger. - */ - final LedgerHandle writelh = bkc.createLedger(digestType, "".getBytes()); - - final int numRecovery = 10; - - final String tmp = "BookKeeper is cool!"; - final CountDownLatch latch = new CountDownLatch(numRecovery); - Thread writethread = new Thread() { - public void run() { - try { - while (true) { - writelh.addEntry(tmp.getBytes()); - latch.countDown(); - } - } catch (Exception e) { - LOG.info("Exception adding entry", e); - } - } - }; - writethread.start(); - - - CyclicBarrier barrier = new CyclicBarrier(numRecovery + 1); - LedgerOpenThread[] threads = new LedgerOpenThread[numRecovery]; - for (int i = 0; i < numRecovery; i++) { - threads[i] = new LedgerOpenThread(i, digestType, writelh.getId(), barrier); - threads[i].start(); - } - latch.await(); - barrier.await(); // should trigger threads to go - - writethread.join(); - long lastConfirmed = writelh.getLastAddConfirmed(); - - for (int i = 0; i < numRecovery; i++) { - threads[i].join(); - assertTrue("Added confirmed is incorrect", - lastConfirmed <= threads[i].getLastConfirmedEntry()); - } - } - - /** - * Test that opening a ledger in norecovery mode - * doesn't fence off a ledger. - */ - @Test - public void testNoRecoveryOpen() throws Exception { - /* - * Create ledger. - */ - LedgerHandle writelh = null; - writelh = bkc.createLedger(digestType, "".getBytes()); - - String tmp = "BookKeeper is cool!"; - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - /* - * Try to open ledger. - */ - LedgerHandle readlh = bkc.openLedgerNoRecovery(writelh.getId(), - digestType, "".getBytes()); - long numReadable = readlh.getLastAddConfirmed(); - LOG.error("numRead " + numReadable); - readlh.readEntries(1, numReadable); - - // should not have triggered recovery and fencing - writelh.addEntry(tmp.getBytes()); - try { - readlh.readEntries(numReadable + 1, numReadable + 1); - fail("Shouldn't have been able to read this far"); - } catch (BKException.BKReadException e) { - // all is good - } - - writelh.addEntry(tmp.getBytes()); - long numReadable2 = readlh.getLastAddConfirmed(); - assertEquals("Number of readable entries hasn't changed", numReadable2, numReadable); - readlh.close(); - - writelh.addEntry(tmp.getBytes()); - writelh.close(); - } - - /** - * create a ledger and write entries. - * kill a bookie in the ensemble. Recover. - * Fence the ledger. Kill another bookie. Recover. - */ - @Test - public void testFencingInteractionWithBookieRecovery() throws Exception { - System.setProperty("digestType", digestType.toString()); - System.setProperty("passwd", "testPasswd"); - - BookKeeperAdmin admin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString()); - - LedgerHandle writelh = bkc.createLedger(digestType, "testPasswd".getBytes()); - - String tmp = "Foobar"; - - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - BookieId bookieToKill = writelh.getLedgerMetadata().getEnsembleAt(numEntries).get(0); - killBookie(bookieToKill); - - // write entries to change ensemble - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - admin.recoverBookieData(bookieToKill); - - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - LedgerHandle readlh = bkc.openLedger(writelh.getId(), - digestType, "testPasswd".getBytes()); - try { - writelh.addEntry(tmp.getBytes()); - LOG.error("Should have thrown an exception"); - fail("Should have thrown an exception when trying to write"); - } catch (BKException.BKLedgerFencedException e) { - // correct behaviour - } - - readlh.close(); - writelh.close(); - } - - /** - * create a ledger and write entries. - * Fence the ledger. Kill a bookie. Recover. - * Ensure that recover doesn't reallow adding - */ - @Test - public void testFencingInteractionWithBookieRecovery2() throws Exception { - System.setProperty("digestType", digestType.toString()); - System.setProperty("passwd", "testPasswd"); - - BookKeeperAdmin admin = new BookKeeperAdmin(zkUtil.getZooKeeperConnectString()); - - LedgerHandle writelh = bkc.createLedger(digestType, "testPasswd".getBytes()); - - String tmp = "Foobar"; - - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - LedgerHandle readlh = bkc.openLedger(writelh.getId(), - digestType, "testPasswd".getBytes()); - // should be fenced by now - BookieId bookieToKill = writelh.getLedgerMetadata().getEnsembleAt(numEntries).get(0); - killBookie(bookieToKill); - admin.recoverBookieData(bookieToKill); - - try { - writelh.addEntry(tmp.getBytes()); - LOG.error("Should have thrown an exception"); - fail("Should have thrown an exception when trying to write"); - } catch (BKException.BKLedgerFencedException e) { - // correct behaviour - } - - readlh.close(); - writelh.close(); - } - - /** - * create a ledger and write entries. - * sleep a bookie - * Ensure that fencing proceeds even with the bookie sleeping - */ - @Test - public void testFencingWithHungBookie() throws Exception { - LedgerHandle writelh = bkc.createLedger(digestType, "testPasswd".getBytes()); - - String tmp = "Foobar"; - - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - CountDownLatch sleepLatch = new CountDownLatch(1); - sleepBookie(writelh.getLedgerMetadata().getAllEnsembles().get(0L).get(1), sleepLatch); - - LedgerHandle readlh = bkc.openLedger(writelh.getId(), - digestType, "testPasswd".getBytes()); - - try { - writelh.addEntry(tmp.getBytes()); - LOG.error("Should have thrown an exception"); - fail("Should have thrown an exception when trying to write"); - } catch (BKException.BKLedgerFencedException e) { - // correct behaviour - } - - sleepLatch.countDown(); - readlh.close(); - writelh.close(); - } - - /** - * Test that fencing doesn't work with a bad password. - */ - @Test - public void testFencingBadPassword() throws Exception { - /* - * Create ledger. - */ - LedgerHandle writelh = null; - writelh = bkc.createLedger(digestType, "password1".getBytes()); - - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < 10; i++) { - writelh.addEntry(tmp.getBytes()); - } - - /* - * Try to open ledger. - */ - try { - bkc.openLedger(writelh.getId(), digestType, "badPassword".getBytes()); - fail("Should not have been able to open with a bad password"); - } catch (BKException.BKUnauthorizedAccessException uue) { - // correct behaviour - } - // should have triggered recovery and fencing - - writelh.addEntry(tmp.getBytes()); - } - - @Test - public void testFencingAndRestartBookies() throws Exception { - LedgerHandle writelh = null; - writelh = bkc.createLedger(digestType, "password".getBytes()); - - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < 10; i++) { - writelh.addEntry(tmp.getBytes()); - } - - /* - * Try to open ledger. - */ - LedgerHandle readlh = bkc.openLedger(writelh.getId(), digestType, - "password".getBytes()); - - restartBookies(); - - try { - writelh.addEntry(tmp.getBytes()); - LOG.error("Should have thrown an exception"); - fail("Should have thrown an exception when trying to write"); - } catch (BKException.BKLedgerFencedException e) { - // correct behaviour - } - - readlh.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestGetBookieInfoTimeout.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestGetBookieInfoTimeout.java deleted file mode 100644 index c402451588b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestGetBookieInfoTimeout.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.apache.bookkeeper.client; - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.concurrent.DefaultThreadFactory; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.BookieInfoReader.BookieInfo; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieClient; -import org.apache.bookkeeper.proto.BookieClientImpl; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GetBookieInfoCallback; -import org.apache.bookkeeper.proto.BookkeeperProtocol; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This unit test tests timeout of GetBookieInfo request. - * - */ -public class TestGetBookieInfoTimeout extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestGetBookieInfoTimeout.class); - DigestType digestType; - public EventLoopGroup eventLoopGroup; - public OrderedExecutor executor; - private ScheduledExecutorService scheduler; - - public TestGetBookieInfoTimeout() { - super(5); - this.digestType = DigestType.CRC32C; - } - - @Before - public void setUp() throws Exception { - super.setUp(); - eventLoopGroup = new NioEventLoopGroup(); - - executor = OrderedExecutor.newBuilder() - .name("BKClientOrderedSafeExecutor") - .numThreads(2) - .build(); - scheduler = Executors.newSingleThreadScheduledExecutor( - new DefaultThreadFactory("BookKeeperClientScheduler")); - } - - @After - public void tearDown() throws Exception { - scheduler.shutdown(); - eventLoopGroup.shutdownGracefully(); - executor.shutdown(); - } - - @Test - public void testGetBookieInfoTimeout() throws Exception { - - // connect to the bookies and create a ledger - LedgerHandle writelh = bkc.createLedger(3, 3, digestType, "testPasswd".getBytes()); - String tmp = "Foobar"; - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - // set timeout for getBookieInfo to be 2 secs and cause one of the bookies to go to sleep for 3X that time - ClientConfiguration cConf = new ClientConfiguration(); - cConf.setGetBookieInfoTimeout(2); - cConf.setReadEntryTimeout(100000); // by default we are using readEntryTimeout for timeouts - - final BookieId bookieToSleep = writelh.getLedgerMetadata().getEnsembleAt(0).get(0); - int sleeptime = cConf.getBookieInfoTimeout() * 3; - CountDownLatch latch = sleepBookie(bookieToSleep, sleeptime); - latch.await(); - - // try to get bookie info from the sleeping bookie. It should fail with timeout error - BookieClient bc = new BookieClientImpl(cConf, eventLoopGroup, UnpooledByteBufAllocator.DEFAULT, executor, - scheduler, NullStatsLogger.INSTANCE, bkc.getBookieAddressResolver()); - long flags = BookkeeperProtocol.GetBookieInfoRequest.Flags.FREE_DISK_SPACE_VALUE - | BookkeeperProtocol.GetBookieInfoRequest.Flags.TOTAL_DISK_CAPACITY_VALUE; - - class CallbackObj { - int rc; - long requested; - @SuppressWarnings("unused") - long freeDiskSpace, totalDiskCapacity; - CountDownLatch latch = new CountDownLatch(1); - CallbackObj(long requested) { - this.requested = requested; - this.rc = 0; - this.freeDiskSpace = 0L; - this.totalDiskCapacity = 0L; - } - } - CallbackObj obj = new CallbackObj(flags); - bc.getBookieInfo(bookieToSleep, flags, new GetBookieInfoCallback() { - @Override - public void getBookieInfoComplete(int rc, BookieInfo bInfo, Object ctx) { - CallbackObj obj = (CallbackObj) ctx; - obj.rc = rc; - if (rc == Code.OK) { - if ((obj.requested & BookkeeperProtocol.GetBookieInfoRequest.Flags.FREE_DISK_SPACE_VALUE) != 0) { - obj.freeDiskSpace = bInfo.getFreeDiskSpace(); - } - if ((obj.requested & BookkeeperProtocol.GetBookieInfoRequest.Flags.TOTAL_DISK_CAPACITY_VALUE) - != 0) { - obj.totalDiskCapacity = bInfo.getTotalDiskSpace(); - } - } - obj.latch.countDown(); - } - - }, obj); - obj.latch.await(); - if (LOG.isDebugEnabled()) { - LOG.debug("Return code: " + obj.rc); - } - assertTrue("GetBookieInfo failed with unexpected error code: " + obj.rc, obj.rc == Code.TimeoutException); - } - - @Test - public void testGetBookieInfoWithAllStoppedBookies() throws Exception { - Map bookieInfo = bkc.getBookieInfo(); - assertEquals(5, bookieInfo.size()); - stopAllBookies(false); - bookieInfo = bkc.getBookieInfo(); - assertEquals(0, bookieInfo.size()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerChecker.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerChecker.java deleted file mode 100644 index 222cd0aac4c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerChecker.java +++ /dev/null @@ -1,533 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests the functionality of LedgerChecker. This Ledger checker should be able - * to detect the correct underReplicated fragment - */ -public class TestLedgerChecker extends BookKeeperClusterTestCase { - private static final byte[] TEST_LEDGER_ENTRY_DATA = "TestCheckerData" - .getBytes(); - private static final byte[] TEST_LEDGER_PASSWORD = "testpasswd".getBytes(); - private static final Logger LOG = LoggerFactory.getLogger(TestLedgerChecker.class); - - public TestLedgerChecker() { - super(3); - } - - class CheckerCallback implements GenericCallback> { - private Set result = null; - private CountDownLatch latch = new CountDownLatch(1); - - public void operationComplete(int rc, Set result) { - this.result = result; - latch.countDown(); - } - - Set waitAndGetResult() throws InterruptedException { - latch.await(); - return result; - } - } - - /** - * Tests that the LedgerChecker should detect the underReplicated fragments - * on multiple Bookie crashes. - */ - @Test - public void testChecker() throws Exception { - - LedgerHandle lh = bkc.createLedger(BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - startNewBookie(); - - for (int i = 0; i < 10; i++) { - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - } - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles() - .get(0L).get(0); - LOG.info("Killing {}", replicaToKill); - killBookie(replicaToKill); - - for (int i = 0; i < 10; i++) { - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - } - - Set result = getUnderReplicatedFragments(lh); - assertNotNull("Result shouldn't be null", result); - for (LedgerFragment r : result) { - LOG.info("unreplicated fragment: {}", r); - } - - assertEquals("Should have one missing fragment", 1, result.size()); - assertTrue("Fragment should be missing from first replica", - result.iterator().next().getAddresses().contains(replicaToKill)); - - BookieId replicaToKill2 = lh.getLedgerMetadata() - .getAllEnsembles().get(0L).get(1); - LOG.info("Killing {}", replicaToKill2); - killBookie(replicaToKill2); - - result = getUnderReplicatedFragments(lh); - assertNotNull("Result shouldn't be null", result); - for (LedgerFragment r : result) { - LOG.info("unreplicated fragment: {}", r); - } - - AtomicInteger number = new AtomicInteger(); - result.forEach(ledgerFragment -> number.addAndGet(ledgerFragment.getAddresses().size())); - assertEquals("Should have three missing fragments", 3, number.get()); - } - - /** - * Tests that ledger checker should pick the fragment as bad only if any of - * the fragment entries not meeting the quorum. - */ - // ///////////////////////////////////////////////////// - // /////////Ensemble = 3, Quorum = 2 /////////////////// - // /Sample Ledger meta data should look like//////////// - // /0 a b c /////*entry present in a,b. Now kill c////// - // /1 a b d //////////////////////////////////////////// - // /Here even though one BK failed at this stage, ////// - // /we don't have any missed entries. Quorum satisfied// - // /So, there should not be any missing replicas./////// - // ///////////////////////////////////////////////////// - @Test - public void testShouldNotGetTheFragmentIfThereIsNoMissedEntry() - throws Exception { - - LedgerHandle lh = bkc.createLedger(3, 2, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - - // Entry should have added in first 2 Bookies. - - // Kill the 3rd BK from ensemble. - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - BookieId lastBookieFromEnsemble = firstEnsemble.get(2); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - - startNewBookie(); - - LOG.info("Ensembles after first entry :" - + lh.getLedgerMetadata().getAllEnsembles()); - - // Adding one more entry. Here enseble should be reformed. - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - - LOG.info("Ensembles after second entry :" - + lh.getLedgerMetadata().getAllEnsembles()); - - Set result = getUnderReplicatedFragments(lh); - - assertNotNull("Result shouldn't be null", result); - - for (LedgerFragment r : result) { - LOG.info("unreplicated fragment: {}", r); - } - - assertEquals("Empty fragment should be considered missing", 1, result.size()); - } - - /** - * Tests that LedgerChecker should give two fragments when 2 bookies failed - * in same ensemble when ensemble = 3, quorum = 2. - */ - @Test - public void testShouldGetTwoFrgamentsIfTwoBookiesFailedInSameEnsemble() - throws Exception { - - LedgerHandle lh = bkc.createLedger(3, 2, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - startNewBookie(); - startNewBookie(); - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - - BookieId firstBookieFromEnsemble = firstEnsemble.get(0); - killBookie(firstEnsemble, firstBookieFromEnsemble); - - BookieId secondBookieFromEnsemble = firstEnsemble.get(1); - killBookie(firstEnsemble, secondBookieFromEnsemble); - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - Set result = getUnderReplicatedFragments(lh); - - assertNotNull("Result shouldn't be null", result); - - for (LedgerFragment r : result) { - LOG.info("unreplicated fragment: {}", r); - } - - assertEquals("Empty fragment should be considered missing", 2, result.size()); - assertEquals("There should be 2 failed bookies in the fragment", - 2, result.iterator().next().getBookiesIndexes().size()); - } - - /** - * Tests that LedgerChecker should not get any underReplicated fragments, if - * corresponding ledger does not exists. - */ - @Test - public void testShouldNotGetAnyFragmentIfNoLedgerPresent() - throws Exception { - - LedgerHandle lh = bkc.createLedger(3, 2, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - BookieId firstBookieFromEnsemble = firstEnsemble.get(0); - killBookie(firstBookieFromEnsemble); - startNewBookie(); - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - bkc.deleteLedger(lh.getId()); - LOG.info("Waiting to see ledger id {} deletion", lh.getId()); - int retries = 40; - boolean noSuchLedger = false; - while (retries > 0) { - try { - lh.readEntries(0, 0); - } catch (BKException.BKNoSuchLedgerExistsException bkn) { - noSuchLedger = true; - break; - } - retries--; - Thread.sleep(500); - } - assertEquals("Ledger exists", true, noSuchLedger); - Set result = getUnderReplicatedFragments(lh); - assertNotNull("Result shouldn't be null", result); - - assertEquals("There should be 0 fragments. But returned fragments are " - + result, 0, result.size()); - } - - /** - * Tests that LedgerChecker should get failed ensemble number of fragments - * if ensemble bookie failures on next entry. - */ - @Test - public void testShouldGetFailedEnsembleNumberOfFgmntsIfEnsembleBookiesFailedOnNextWrite() - throws Exception { - - startNewBookie(); - startNewBookie(); - LedgerHandle lh = bkc.createLedger(3, 2, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - for (int i = 0; i < 3; i++) { - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - } - - // Kill all three bookies - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - for (BookieId bkAddr : firstEnsemble) { - killBookie(firstEnsemble, bkAddr); - } - - Set result = getUnderReplicatedFragments(lh); - - assertNotNull("Result shouldn't be null", result); - - for (LedgerFragment r : result) { - LOG.info("unreplicated fragment: {}", r); - } - - assertEquals("There should be 1 fragments", 1, result.size()); - assertEquals("There should be 3 failed bookies in the fragment", - 3, result.iterator().next().getBookiesIndexes().size()); - } - - /** - * Tests that LedgerChecker should not get any fragments as underReplicated - * if Ledger itself is empty. - */ - @Test - public void testShouldNotGetAnyFragmentWithEmptyLedger() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 2, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - Set result = getUnderReplicatedFragments(lh); - assertNotNull("Result shouldn't be null", result); - assertEquals("There should be 0 fragments. But returned fragments are " - + result, 0, result.size()); - } - - /** - * Tests that LedgerChecker should get all fragments if ledger is empty - * but all bookies in the ensemble are down. - * In this case, there's no way to tell whether data was written or not. - * In this case, there'll only be two fragments, as quorum is 2 and we only - * suspect that the first entry of the ledger could exist. - */ - @Test - public void testShouldGet2FragmentsWithEmptyLedgerButBookiesDead() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 2, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - for (BookieId b : lh.getLedgerMetadata().getAllEnsembles().get(0L)) { - killBookie(b); - } - Set result = getUnderReplicatedFragments(lh); - assertNotNull("Result shouldn't be null", result); - assertEquals("There should be 1 fragments.", 1, result.size()); - assertEquals("There should be 3 failed bookies in the fragment", - 3, result.iterator().next().getBookiesIndexes().size()); - } - - /** - * Tests that LedgerChecker should one fragment as underReplicated - * if there is an open ledger with single entry written. - */ - @Test - public void testShouldGetOneFragmentWithSingleEntryOpenedLedger() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - BookieId lastBookieFromEnsemble = firstEnsemble.get(0); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - - startNewBookie(); - - //Open ledger separately for Ledger checker. - LedgerHandle lh1 = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - - Set result = getUnderReplicatedFragments(lh1); - assertNotNull("Result shouldn't be null", result); - assertEquals("There should be 1 fragment. But returned fragments are " - + result, 1, result.size()); - assertEquals("There should be 1 failed bookies in the fragment", - 1, result.iterator().next().getBookiesIndexes().size()); - } - - /** - * Tests that LedgerChecker correctly identifies missing fragments - * when a single entry is written after an ensemble change. - * This is important, as the last add confirmed may be less than the - * first entry id of the final segment. - */ - @Test - public void testSingleEntryAfterEnsembleChange() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - for (int i = 0; i < 10; i++) { - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - } - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - DistributionSchedule.WriteSet writeSet = lh.getDistributionSchedule().getWriteSet(lh.getLastAddPushed()); - BookieId lastBookieFromEnsemble = firstEnsemble.get(writeSet.get(0)); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - startNewBookie(); - - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - - writeSet = lh.getDistributionSchedule().getWriteSet( - lh.getLastAddPushed()); - lastBookieFromEnsemble = firstEnsemble.get(writeSet.get(1)); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - - //Open ledger separately for Ledger checker. - LedgerHandle lh1 = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - - Set result = getUnderReplicatedFragments(lh1); - assertNotNull("Result shouldn't be null", result); - assertEquals("There should be 2 fragments. But returned fragments are " - + result, 2, result.size()); - for (LedgerFragment lf : result) { - if (lf.getFirstEntryId() == 0L) { - assertEquals("There should be 2 failed bookies in first fragment", - 2, lf.getBookiesIndexes().size()); - } else { - assertEquals("There should be 1 failed bookie in second fragment", - 1, lf.getBookiesIndexes().size()); - } - } - } - - /** - * Tests that LedgerChecker does not return any fragments - * from a closed ledger with 0 entries. - */ - @Test - public void testClosedEmptyLedger() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - lh.close(); - - BookieId lastBookieFromEnsemble = firstEnsemble.get(0); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - - //Open ledger separately for Ledger checker. - LedgerHandle lh1 = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - - Set result = getUnderReplicatedFragments(lh1); - assertNotNull("Result shouldn't be null", result); - assertEquals("Empty fragment should be considered missing" - + result, 1, result.size()); - } - - /** - * Tests that LedgerChecker does not return any fragments - * from a closed ledger with 0 entries. - */ - @Test - public void testClosedSingleEntryLedger() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 2, BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - List firstEnsemble = lh.getLedgerMetadata() - .getAllEnsembles().get(0L); - lh.addEntry(TEST_LEDGER_ENTRY_DATA); - lh.close(); - - // kill bookie 2 - BookieId lastBookieFromEnsemble = firstEnsemble.get(2); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - - //Open ledger separately for Ledger checker. - LedgerHandle lh1 = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - - Set result = getUnderReplicatedFragments(lh1); - assertNotNull("Result shouldn't be null", result); - assertEquals("Empty fragment should be considered missing" - + result, 1, result.size()); - lh1.close(); - - // kill bookie 1 - lastBookieFromEnsemble = firstEnsemble.get(1); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - startNewBookie(); - - //Open ledger separately for Ledger checker. - lh1 = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - - result = getUnderReplicatedFragments(lh1); - assertNotNull("Result shouldn't be null", result); - assertEquals("There should be 1 fragment. But returned fragments are " - + result, 1, result.size()); - assertEquals("There should be 2 failed bookies in the fragment", - 2, result.iterator().next().getBookiesIndexes().size()); - lh1.close(); - - // kill bookie 0 - lastBookieFromEnsemble = firstEnsemble.get(0); - LOG.info("Killing " + lastBookieFromEnsemble + " from ensemble=" - + firstEnsemble); - killBookie(lastBookieFromEnsemble); - startNewBookie(); - - //Open ledger separately for Ledger checker. - lh1 = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, - TEST_LEDGER_PASSWORD); - - result = getUnderReplicatedFragments(lh1); - assertNotNull("Result shouldn't be null", result); - assertEquals("There should be 1 fragment. But returned fragments are " - + result, 1, result.size()); - assertEquals("There should be 3 failed bookies in the fragment", - 3, result.iterator().next().getBookiesIndexes().size()); - lh1.close(); - } - - @Test - public void testVerifyLedgerFragmentSkipsUnavailableBookie() throws Exception { - // Initialize LedgerChecker with mocked watcher to validate interactions - BookieWatcher bookieWatcher = mock(BookieWatcher.class); - when(bookieWatcher.isBookieUnavailable(any())).thenReturn(true); - LedgerChecker mockedChecker = new LedgerChecker(bkc.getBookieClient(), bookieWatcher); - - LedgerHandle ledgerHandle = bkc.createLedger(BookKeeper.DigestType.CRC32, TEST_LEDGER_PASSWORD); - - // Add entries to ensure the right code path is validated - ledgerHandle.addEntry(TEST_LEDGER_ENTRY_DATA); - ledgerHandle.addEntry(TEST_LEDGER_ENTRY_DATA); - ledgerHandle.addEntry(TEST_LEDGER_ENTRY_DATA); - - CheckerCallback cb = new CheckerCallback(); - mockedChecker.checkLedger(ledgerHandle, cb); - Set result = cb.waitAndGetResult(); - - // Note that the bookieWatcher mock is set to make the ledger underreplicated - assertEquals("The one ledger should be considered underreplicated.", 1, result.size()); - verify(bookieWatcher, times(3)).isBookieUnavailable(any()); - } - - private Set getUnderReplicatedFragments(LedgerHandle lh) - throws InterruptedException { - LedgerChecker checker = new LedgerChecker(bkc, 1); - CheckerCallback cb = new CheckerCallback(); - checker.checkLedger(lh, cb); - Set result = cb.waitAndGetResult(); - return result; - } - - private void killBookie(List firstEnsemble, BookieId ensemble) - throws Exception { - LOG.info("Killing " + ensemble + " from ensemble=" + firstEnsemble); - killBookie(ensemble); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplication.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplication.java deleted file mode 100644 index b67caaae172..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplication.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; -import java.util.SortedMap; -import java.util.concurrent.CountDownLatch; -import java.util.function.BiConsumer; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests BKAdmin that it should be able to replicate the failed bookie fragments - * to target bookie. - */ -public class TestLedgerFragmentReplication extends BookKeeperClusterTestCase { - - private static final byte[] TEST_PSSWD = "testpasswd".getBytes(); - private static final DigestType TEST_DIGEST_TYPE = BookKeeper.DigestType.CRC32; - private static final BiConsumer NOOP_BICONSUMER = (l, e) -> { }; - private static final Logger LOG = LoggerFactory - .getLogger(TestLedgerFragmentReplication.class); - - public TestLedgerFragmentReplication() { - super(3); - } - - private static class CheckerCallback implements - GenericCallback> { - private Set result = null; - private CountDownLatch latch = new CountDownLatch(1); - - Set waitAndGetResult() throws InterruptedException { - latch.await(); - return result; - } - - @Override - public void operationComplete(int rc, Set result) { - this.result = result; - latch.countDown(); - } - } - - /** - * Tests that replicate method should replicate the failed bookie fragments - * to target bookie passed. - */ - @Test - public void testReplicateLFShouldCopyFailedBookieFragmentsToTargetBookie() - throws Exception { - byte[] data = "TestLedgerFragmentReplication".getBytes(); - LedgerHandle lh = bkc.createLedger(3, 3, TEST_DIGEST_TYPE, - TEST_PSSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles() - .get(0L).get(0); - - LOG.info("Killing Bookie : {}", replicaToKill); - killBookie(replicaToKill); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - - Set result = getFragmentsToReplicate(lh); - - BookKeeperAdmin admin = new BookKeeperAdmin(baseClientConf); - lh.close(); - // 0-9 entries should be copy to new bookie - - for (LedgerFragment lf : result) { - admin.replicateLedgerFragment(lh, lf, NOOP_BICONSUMER); - } - - // Killing all bookies except newly replicated bookie - SortedMap> allBookiesBeforeReplication = lh - .getLedgerMetadata().getAllEnsembles(); - for (Entry> entry : allBookiesBeforeReplication.entrySet()) { - List bookies = entry.getValue(); - for (BookieId bookie : bookies) { - if (newBkAddr.equals(bookie)) { - continue; - } - killBookie(bookie); - } - } - - // Should be able to read the entries from 0-9 - verifyRecoveredLedgers(lh, 0, 9); - } - - /** - * Tests that fragment re-replication fails on last unclosed ledger - * fragments. - */ - @Test - public void testReplicateLFFailsOnlyOnLastUnClosedFragments() - throws Exception { - byte[] data = "TestLedgerFragmentReplication".getBytes(); - LedgerHandle lh = bkc.createLedger(3, 3, TEST_DIGEST_TYPE, - TEST_PSSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles() - .get(0L).get(0); - - startNewBookie(); - LOG.info("Killing Bookie : {}", replicaToKill); - killBookie(replicaToKill); - - // Lets reform ensemble - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - - BookieId replicaToKill2 = lh.getLedgerMetadata() - .getAllEnsembles().get(0L).get(1); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - - LOG.info("Killing Bookie : {}", replicaToKill2); - killBookie(replicaToKill2); - - Set result = getFragmentsToReplicate(lh); - - BookKeeperAdmin admin = new BookKeeperAdmin(baseClientConf); - // 0-9 entries should be copy to new bookie - - int unclosedCount = 0; - for (LedgerFragment lf : result) { - if (lf.isClosed()) { - admin.replicateLedgerFragment(lh, lf, NOOP_BICONSUMER); - } else { - unclosedCount++; - try { - admin.replicateLedgerFragment(lh, lf, NOOP_BICONSUMER); - fail("Shouldn't be able to rereplicate unclosed ledger"); - } catch (BKException bke) { - // correct behaviour - } - } - } - assertEquals("Should be only one unclosed fragment", 1, unclosedCount); - } - - /** - * Tests that ReplicateLedgerFragment should return false if replication - * fails. - */ - @Test - public void testReplicateLFShouldReturnFalseIfTheReplicationFails() - throws Exception { - byte[] data = "TestLedgerFragmentReplication".getBytes(); - LedgerHandle lh = bkc.createLedger(2, 1, TEST_DIGEST_TYPE, - TEST_PSSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - - // Kill the first Bookie - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles() - .get(0L).get(0); - killBookie(replicaToKill); - LOG.info("Killed Bookie =" + replicaToKill); - - // Write some more entries - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - // Kill the second Bookie - replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - killBookie(replicaToKill); - LOG.info("Killed Bookie =" + replicaToKill); - - Set fragments = getFragmentsToReplicate(lh); - BookKeeperAdmin admin = new BookKeeperAdmin(baseClientConf); - for (LedgerFragment lf : fragments) { - try { - admin.replicateLedgerFragment(lh, lf, NOOP_BICONSUMER); - } catch (BKException.BKLedgerRecoveryException e) { - // expected - } - } - } - - /** - * Tests that splitIntoSubFragment should be able to split the original - * passed fragment into sub fragments at correct boundaries. - */ - @Test - public void testSplitIntoSubFragmentsWithDifferentFragmentBoundaries() - throws Exception { - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId()); - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(124L).withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .withPassword(TEST_PSSWD).withDigestType(TEST_DIGEST_TYPE.toApiDigestType()) - .withClosedState().withLastEntryId(-1).withLength(0) - .newEnsembleEntry(0L, ensemble) - .build(); - - LedgerHandle lh = new LedgerHandle(bkc.getClientCtx(), 0, - new Versioned<>(metadata, new LongVersion(0L)), - TEST_DIGEST_TYPE, - TEST_PSSWD, WriteFlag.NONE); - testSplitIntoSubFragments(10, 21, -1, 1, lh); - testSplitIntoSubFragments(10, 21, 20, 1, lh); - testSplitIntoSubFragments(0, 0, 10, 1, lh); - testSplitIntoSubFragments(0, 1, 1, 2, lh); - testSplitIntoSubFragments(20, 24, 2, 3, lh); - testSplitIntoSubFragments(21, 32, 3, 4, lh); - testSplitIntoSubFragments(22, 103, 11, 8, lh); - testSplitIntoSubFragments(49, 51, 1, 3, lh); - testSplitIntoSubFragments(11, 101, 3, 31, lh); - testSplitIntoSubFragments(0, -1, 1, 1, lh); - testSplitIntoSubFragments(0, -1, 10, 1, lh); - } - - /** - * Assert the sub-fragment boundaries. - */ - void testSplitIntoSubFragments(final long oriFragmentFirstEntry, - final long oriFragmentLastEntry, long entriesPerSubFragment, - long expectedSubFragments, LedgerHandle lh) { - LedgerFragment fr = new LedgerFragment(lh, oriFragmentFirstEntry, - oriFragmentLastEntry, Sets.newHashSet(0)); - Set subFragments = LedgerFragmentReplicator - .splitIntoSubFragments(lh, fr, entriesPerSubFragment); - assertEquals(expectedSubFragments, subFragments.size()); - int fullSubFragment = 0; - int partialSubFragment = 0; - for (LedgerFragment ledgerFragment : subFragments) { - if ((ledgerFragment.getLastKnownEntryId() - - ledgerFragment.getFirstEntryId() + 1) == entriesPerSubFragment) { - fullSubFragment++; - } else { - long totalEntriesToReplicate = oriFragmentLastEntry - - oriFragmentFirstEntry + 1; - if (entriesPerSubFragment <= 0 - || totalEntriesToReplicate / entriesPerSubFragment == 0) { - assertEquals( - "FirstEntryId should be same as original fragment's firstEntryId", - fr.getFirstEntryId(), ledgerFragment - .getFirstEntryId()); - assertEquals( - "LastEntryId should be same as original fragment's lastEntryId", - fr.getLastKnownEntryId(), ledgerFragment - .getLastKnownEntryId()); - } else { - long partialSplitEntries = totalEntriesToReplicate - % entriesPerSubFragment; - assertEquals( - "Partial fragment with wrong entry boundaries", - ledgerFragment.getLastKnownEntryId() - - ledgerFragment.getFirstEntryId() + 1, - partialSplitEntries); - } - partialSubFragment++; - } - } - assertEquals("Unexpected number of sub fargments", fullSubFragment - + partialSubFragment, expectedSubFragments); - assertTrue("There should be only one or zero partial sub Fragment", - partialSubFragment == 0 || partialSubFragment == 1); - } - - private Set getFragmentsToReplicate(LedgerHandle lh) - throws InterruptedException { - LedgerChecker checker = new LedgerChecker(bkc); - CheckerCallback cb = new CheckerCallback(); - checker.checkLedger(lh, cb); - Set fragments = cb.waitAndGetResult(); - return fragments; - } - - private void verifyRecoveredLedgers(LedgerHandle lh, long startEntryId, - long endEntryId) throws BKException, InterruptedException { - LedgerHandle lhs = bkc.openLedgerNoRecovery(lh.getId(), - TEST_DIGEST_TYPE, TEST_PSSWD); - Enumeration entries = lhs.readEntries(startEntryId, - endEntryId); - assertTrue("Should have the elements", entries.hasMoreElements()); - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertEquals("TestLedgerFragmentReplication", new String(entry - .getEntry())); - } - } - - @Test - public void testSplitLedgerFragmentState() throws Exception { - int lastEntryId = 10; - int rereplicationEntryBatchSize = 10; - - List ensemble = new ArrayList(); - ensemble.add(BookieId.parse("bookie0:3181")); - ensemble.add(BookieId.parse("bookie1:3181")); - ensemble.add(BookieId.parse("bookie2:3181")); - ensemble.add(BookieId.parse("bookie3:3181")); - ensemble.add(BookieId.parse("bookie4:3181")); - ensemble.add(BookieId.parse("bookie5:3181")); - ensemble.add(BookieId.parse("bookie6:3181")); - - LedgerMetadataBuilder builder = LedgerMetadataBuilder.create(); - builder.withId(124L).withEnsembleSize(7).withWriteQuorumSize(3).withAckQuorumSize(2) - .withDigestType(TEST_DIGEST_TYPE.toApiDigestType()).withPassword(TEST_PSSWD) - .newEnsembleEntry(0, ensemble).withLastEntryId(lastEntryId).withLength(512).withClosedState(); - LedgerMetadata met = builder.build(); - - LedgerHandle lh = new LedgerHandle(bkc.getClientCtx(), 100L, new Versioned<>(met, new LongVersion(0L)), - TEST_DIGEST_TYPE, TEST_PSSWD, EnumSet.noneOf(WriteFlag.class)); - - /* - * create LedgerFragment from the ledger ensemble for the bookies with - * indexes 1 and 5. - */ - Set bookieIndexes = new HashSet<>(); - bookieIndexes.add(1); - bookieIndexes.add(5); - LedgerFragment lfrag = new LedgerFragment(lh, 0, 10, bookieIndexes); - - /* - * Since this ledger contains 11 entries (lastEntryId is 10), when it is - * split into subFragments of size 10 it will be split into 2. In the - * first subfragment, firstEntryID (and firstStoredEntryId) will be 0. - * lastKnownEntryID will be 9 but lastStoredEntryId will be 8. Because - * entry 9 will not be stored in both of the nodes and entry 8 is the - * last entry that is stored in either one of the node. - * - * In the second sub-fragment firstEntryID, firstStoredEntryId, - * lastKnownEntryID and lastStoredEntryId should be 10. - */ - Set partionedFragments = LedgerFragmentReplicator.splitIntoSubFragments(lh, lfrag, - rereplicationEntryBatchSize); - assertEquals("Number of sub-fragments", 2, partionedFragments.size()); - for (LedgerFragment partionedFragment : partionedFragments) { - if (partionedFragment.getFirstEntryId() == 0) { - validateEntryIds(partionedFragment, 0, 0, 9, 8); - } else { - validateEntryIds(partionedFragment, 10, 10, 10, 10); - } - } - } - - private void validateEntryIds(LedgerFragment partionedFragment, long expectedFirstEntryId, - long expectedFirstStoredEntryId, long expectedLastKnownEntryID, long expectedLastStoredEntryId) { - assertEquals("FirstEntryId", expectedFirstEntryId, partionedFragment.getFirstEntryId()); - assertEquals("FirstStoredEntryId", expectedFirstStoredEntryId, partionedFragment.getFirstStoredEntryId()); - assertEquals("LastKnownEntryID", expectedLastKnownEntryID, partionedFragment.getLastKnownEntryId()); - assertEquals("LastStoredEntryId", expectedLastStoredEntryId, partionedFragment.getLastStoredEntryId()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplicationWithMock.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplicationWithMock.java deleted file mode 100644 index c618aa4a15b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplicationWithMock.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.lang.reflect.Field; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.client.impl.LedgerEntryImpl; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieClientImpl; -import org.apache.bookkeeper.proto.BookieProtoEncoding; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.proto.checksum.DummyDigestManager; -import org.apache.commons.collections4.IteratorUtils; -import org.apache.zookeeper.AsyncCallback; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestLedgerFragmentReplicationWithMock { - - @Test - public void testRecoverLedgerFragmentEntrySendRightRequestWithFlag() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - BookieClientImpl bookieClient = Mockito.mock(BookieClientImpl.class); - doAnswer(invocationOnMock -> { - ByteBuf toSend = invocationOnMock.getArgument(4); - BookieProtoEncoding.RequestEnDeCoderPreV3 deCoderPreV3 = - new BookieProtoEncoding.RequestEnDeCoderPreV3(null); - toSend.readerIndex(4); - BookieProtocol.ParsedAddRequest request = (BookieProtocol.ParsedAddRequest) deCoderPreV3.decode(toSend); - - Field flagField = request.getClass().getSuperclass().getDeclaredField("flags"); - flagField.setAccessible(true); - short flag = flagField.getShort(request); - assertEquals(flag, BookieProtocol.FLAG_RECOVERY_ADD); - latch.countDown(); - return null; - }).when(bookieClient) - .addEntry(any(), anyLong(), any(), anyLong(), any(), any(), any(), anyInt(), anyBoolean(), any()); - - BookKeeper bkc = Mockito.mock(BookKeeper.class); - when(bkc.getBookieClient()).thenReturn(bookieClient); - - LedgerHandle lh = Mockito.mock(LedgerHandle.class); - DummyDigestManager ds = new DummyDigestManager(1L, true, ByteBufAllocator.DEFAULT); - when(lh.getDigestManager()).thenReturn(ds); - when(lh.getLedgerKey()).thenReturn(DigestManager.generateMasterKey("".getBytes())); - - ByteBuf data = Unpooled.wrappedBuffer(new byte[1024]); - LedgerEntry entry = new LedgerEntry(LedgerEntryImpl.create(1L, 1L, data.readableBytes(), data)); - List list = new LinkedList<>(); - list.add(entry); - Enumeration entries = IteratorUtils.asEnumeration(list.iterator()); - doAnswer(invocation -> { - org.apache.bookkeeper.client.AsyncCallback.ReadCallback rc = - invocation.getArgument(2, org.apache.bookkeeper.client.AsyncCallback.ReadCallback.class); - rc.readComplete(0, lh, entries, null); - return null; - }).when(lh).asyncReadEntries(anyLong(), anyLong(), any(), any()); - - ClientConfiguration conf = new ClientConfiguration(); - LedgerFragmentReplicator lfr = new LedgerFragmentReplicator(bkc, conf); - - Set bookies = new HashSet<>(); - bookies.add(BookieId.parse("127.0.0.1:3181")); - - AsyncCallback.VoidCallback vc = new AsyncCallback.VoidCallback() { - @Override - public void processResult(int rc, String path, Object ctx) { - } - }; - - lfr.recoverLedgerFragmentEntry(1L, lh, vc, bookies, (lid, le) -> {}); - - latch.await(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxEnsembleChangeNum.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxEnsembleChangeNum.java deleted file mode 100644 index 3015bef64a0..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxEnsembleChangeNum.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.api.BKException.Code.WriteException; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.nio.ByteBuffer; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.junit.Test; - -/** - * Test ensemble change has a max num. - */ -public class TestMaxEnsembleChangeNum extends MockBookKeeperTestCase { - - private static final byte[] password = new byte[5]; - private static final byte[] data = new byte[5]; - - @Test - public void testChangeEnsembleMaxNumWithWriter() throws Exception { - long lId; - int numEntries = 5; - int changeNum = 5; - setBookKeeperConfig(new ClientConfiguration().setDelayEnsembleChange(false).setMaxAllowedEnsembleChanges(5)); - try (WriteHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(3) - .withWriteQuorumSize(3) - .withEnsembleSize(3) - .withPassword(password) - .execute())) { - lId = writer.getId(); - //first fragment - for (int i = 0; i < numEntries; i++) { - writer.append(ByteBuffer.wrap(data)); - } - assertEquals("There should be zero ensemble change", - 1, getLedgerMetadata(lId).getAllEnsembles().size()); - - simulateEnsembleChangeWithWriter(changeNum, numEntries, writer); - - // one more ensemble change - startNewBookie(); - killBookie(writer.getLedgerMetadata().getEnsembleAt(writer.getLastAddConfirmed()).get(0)); - // add failure - try { - writer.append(ByteBuffer.wrap(data)); - fail("should not come to here"); - } catch (BKException exception){ - assertEquals(exception.getCode(), WriteException); - } - } - } - - private void simulateEnsembleChangeWithWriter(int changeNum, int numEntries, WriteHandle writer) throws Exception{ - - int expectedSize = writer.getLedgerMetadata().getAllEnsembles().size() + 1; - //kill bookie and add again - for (int num = 0; num < changeNum; num++){ - startNewBookie(); - - killBookie(writer.getLedgerMetadata().getEnsembleAt(writer.getLastAddConfirmed()).get(0)); - for (int i = 0; i < numEntries; i++) { - writer.append(ByteBuffer.wrap(data)); - } - // ensure there is a ensemble changed - assertEquals("There should be one ensemble change", - expectedSize + num, writer.getLedgerMetadata().getAllEnsembles().size()); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxSizeWorkersQueue.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxSizeWorkersQueue.java deleted file mode 100644 index 3487566a87e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxSizeWorkersQueue.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.Enumeration; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Test the maximum size of a worker queue. - */ -public class TestMaxSizeWorkersQueue extends BookKeeperClusterTestCase { - DigestType digestType = DigestType.CRC32; - - public TestMaxSizeWorkersQueue() { - super(1); - - baseConf.setNumReadWorkerThreads(1); - baseConf.setNumAddWorkerThreads(1); - - // Configure very small queue sizes - baseConf.setMaxPendingReadRequestPerThread(1); - baseConf.setMaxPendingAddRequestPerThread(1); - } - - @Test - public void testReadRejected() throws Exception { - LedgerHandle lh = bkc.createLedger(1, 1, digestType, new byte[0]); - byte[] content = new byte[100]; - - final int n = 1000; - // Write few entries - for (int i = 0; i < n; i++) { - lh.addEntry(content); - } - - // Read asynchronously: - // - 1st read must always succeed - // - Subsequent reads may fail, depending on timing - // - At least few, we expect to fail with TooManyRequestException - final CountDownLatch counter = new CountDownLatch(2); - - final AtomicInteger rcFirstReadOperation = new AtomicInteger(); - - lh.asyncReadEntries(0, 0, new ReadCallback() { - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - rcFirstReadOperation.set(rc); - counter.countDown(); - } - }, lh); - - final AtomicInteger rcSecondReadOperation = new AtomicInteger(); - - lh.asyncReadEntries(0, n - 1, new ReadCallback() { - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - rcSecondReadOperation.set(rc); - counter.countDown(); - } - }, lh); - - counter.await(); - - assertEquals(BKException.Code.OK, rcFirstReadOperation.get()); - assertEquals(BKException.Code.TooManyRequestsException, rcSecondReadOperation.get()); - } - - @Test - public void testAddRejected() throws Exception { - LedgerHandle lh = bkc.createLedger(1, 1, digestType, new byte[0]); - byte[] content = new byte[100]; - - final int n = 1000; - - // Write asynchronously, and expect at least few writes to have failed with NotEnoughBookies, - // because when we get the TooManyRequestException, the client will try to form a new ensemble and that - // operation will fail since we only have 1 bookie available - final CountDownLatch counter = new CountDownLatch(n); - final AtomicBoolean receivedTooManyRequestsException = new AtomicBoolean(); - - // Write few entries - for (int i = 0; i < n; i++) { - lh.asyncAddEntry(content, new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - if (rc == BKException.Code.NotEnoughBookiesException) { - receivedTooManyRequestsException.set(true); - } - - counter.countDown(); - } - }, null); - } - - counter.await(); - - assertTrue(receivedTooManyRequestsException.get()); - } - - @Test - public void testRecoveryNotRejected() throws Exception { - LedgerHandle lh = bkc.createLedger(1, 1, digestType, new byte[0]); - byte[] content = new byte[100]; - - final int numEntriesToRead = 1000; - // Write few entries - for (int i = 0; i < numEntriesToRead; i++) { - lh.addEntry(content); - } - - final int numLedgersToRecover = 10; - List ledgersToRecover = Lists.newArrayList(); - for (int i = 0; i < numLedgersToRecover; i++) { - LedgerHandle lhr = bkc.createLedger(1, 1, digestType, new byte[0]); - lhr.addEntry(content); - // Leave the ledger in open state - ledgersToRecover.add(lhr.getId()); - } - - ExecutorService executor = Executors.newCachedThreadPool(); - final CyclicBarrier barrier = new CyclicBarrier(1 + numLedgersToRecover); - - List> futures = Lists.newArrayList(); - futures.add(executor.submit(new Callable() { - @Override - public Void call() throws Exception { - barrier.await(); - try { - lh.readEntries(0, numEntriesToRead - 1); - fail("Should have thrown exception"); - } catch (Exception e) { - // Expected - } - return null; - } - })); - - for (long ledgerId : ledgersToRecover) { - futures.add(executor.submit(new Callable() { - @Override - public Void call() throws Exception { - barrier.await(); - - // Recovery should always succeed - bkc.openLedger(ledgerId, digestType, new byte[0]); - return null; - } - })); - } - - for (Future future : futures) { - future.get(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestParallelRead.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestParallelRead.java deleted file mode 100644 index 423e02b4aad..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestParallelRead.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.util.Iterator; -import java.util.List; -import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerEntry; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit tests for parallel reading. - */ -public class TestParallelRead extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(TestParallelRead.class); - - final DigestType digestType; - final byte[] passwd = "parallel-read".getBytes(); - - public TestParallelRead() { - super(6); - this.digestType = DigestType.CRC32; - } - - long getLedgerToRead(int ensemble, int writeQuorum, int ackQuorum, int numEntries) - throws Exception { - LedgerHandle lh = bkc.createLedger(ensemble, writeQuorum, ackQuorum, digestType, passwd); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("" + i).getBytes()); - } - lh.close(); - return lh.getId(); - } - - PendingReadOp createReadOp(LedgerHandle lh, long from, long to) { - return new PendingReadOp(lh, bkc.getClientCtx(), from, to, false); - } - - PendingReadOp createRecoveryReadOp(LedgerHandle lh, long from, long to) { - return new PendingReadOp(lh, bkc.getClientCtx(), from, to, true); - } - - @Test - public void testNormalParallelRead() throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 2, 2, numEntries); - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - // read single entry - for (int i = 0; i < numEntries; i++) { - PendingReadOp readOp = createReadOp(lh, i, i); - readOp.parallelRead(true).submit(); - Iterator entries = readOp.future().get().iterator(); - assertTrue(entries.hasNext()); - LedgerEntry entry = entries.next(); - assertNotNull(entry); - assertEquals(i, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - assertFalse(entries.hasNext()); - } - - // read multiple entries - PendingReadOp readOp = createReadOp(lh, 0, numEntries - 1); - readOp.parallelRead(true).submit(); - Iterator iterator = readOp.future().get().iterator(); - - int numReads = 0; - while (iterator.hasNext()) { - LedgerEntry entry = iterator.next(); - assertNotNull(entry); - assertEquals(numReads, Integer.parseInt(new String(entry.getEntryBytes()))); - entry.close(); - ++numReads; - } - assertEquals(numEntries, numReads); - - lh.close(); - } - - private static void expectFail(CompletableFuture future, int expectedRc) { - try { - result(future); - fail("Expect to fail"); - } catch (Exception e) { - assertTrue(e instanceof BKException); - BKException bke = (BKException) e; - assertEquals(expectedRc, bke.getCode()); - } - } - - @Test - public void testParallelReadMissingEntries() throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 2, 2, numEntries); - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - // read single entry - PendingReadOp readOp = createReadOp(lh, 11, 11); - readOp.parallelRead(true).submit(); - expectFail(readOp.future(), Code.NoSuchEntryException); - - // read multiple entries - readOp = createReadOp(lh, 8, 11); - readOp.parallelRead(true).submit(); - expectFail(readOp.future(), Code.NoSuchEntryException); - - lh.close(); - } - - @Test - public void testFailParallelRecoveryReadMissingEntryImmediately() throws Exception { - int numEntries = 1; - - long id = getLedgerToRead(5, 5, 3, numEntries); - - ClientConfiguration newConf = new ClientConfiguration() - .setReadEntryTimeout(30000); - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper newBk = new BookKeeper(newConf); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = lh.getLedgerMetadata().getEnsembleAt(10); - CountDownLatch latch1 = new CountDownLatch(1); - CountDownLatch latch2 = new CountDownLatch(1); - // sleep two bookie - sleepBookie(ensemble.get(0), latch1); - sleepBookie(ensemble.get(1), latch2); - - PendingReadOp readOp = createRecoveryReadOp(lh, 10, 10); - readOp.parallelRead(true).submit(); - // would fail immediately if found missing entries don't cover ack quorum - expectFail(readOp.future(), Code.NoSuchEntryException); - latch1.countDown(); - latch2.countDown(); - - lh.close(); - newBk.close(); - } - - @Test - public void testParallelReadWithFailedBookies() throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 3, 3, numEntries); - - ClientConfiguration newConf = new ClientConfiguration() - .setReadEntryTimeout(30000); - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper newBk = new BookKeeper(newConf); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = lh.getLedgerMetadata().getEnsembleAt(5); - // kill two bookies - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - - // read multiple entries - PendingReadOp readOp = createReadOp(lh, 0, numEntries - 1); - readOp.parallelRead(true).submit(); - Iterator entries = readOp.future().get().iterator(); - - int numReads = 0; - while (entries.hasNext()) { - LedgerEntry entry = entries.next(); - assertNotNull(entry); - assertEquals(numReads, Integer.parseInt(new String(entry.getEntryBytes()))); - ++numReads; - } - assertEquals(numEntries, numReads); - - lh.close(); - newBk.close(); - } - - @Test - public void testParallelReadFailureWithFailedBookies() throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 3, 3, numEntries); - - ClientConfiguration newConf = new ClientConfiguration() - .setReadEntryTimeout(30000); - newConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper newBk = new BookKeeper(newConf); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = lh.getLedgerMetadata().getEnsembleAt(5); - // kill two bookies - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - killBookie(ensemble.get(2)); - - // read multiple entries - PendingReadOp readOp = createReadOp(lh, 0, numEntries - 1); - readOp.parallelRead(true).submit(); - expectFail(readOp.future(), Code.BookieHandleNotAvailableException); - - lh.close(); - newBk.close(); - } - - @Test - public void testLedgerEntryRequestComplete() throws Exception { - LedgerHandle lh = mock(LedgerHandle.class); - LedgerMetadata ledgerMetadata = mock(LedgerMetadata.class); - ClientContext clientContext = mock(ClientContext.class); - ClientInternalConf clientInternalConf = mock(ClientInternalConf.class); - doReturn(clientInternalConf).when(clientContext).getConf(); - BookKeeperClientStats bookKeeperClientStats = mock(BookKeeperClientStats.class); - doReturn(bookKeeperClientStats).when(clientContext).getClientStats(); - OpStatsLogger opStatsLogger = mock(OpStatsLogger.class); - doReturn(opStatsLogger).when(bookKeeperClientStats).getReadOpLogger(); - doReturn(ledgerMetadata).when(lh).getLedgerMetadata(); - doReturn(2).when(ledgerMetadata).getWriteQuorumSize(); - doReturn(1).when(ledgerMetadata).getAckQuorumSize(); - doReturn(new TreeMap<>()).when(ledgerMetadata).getAllEnsembles(); - DistributionSchedule.WriteSet writeSet = mock(DistributionSchedule.WriteSet.class); - doReturn(writeSet).when(lh).getWriteSetForReadOperation(anyLong()); - PendingReadOp pendingReadOp = new PendingReadOp(lh, clientContext, 1, 2, false); - pendingReadOp.parallelRead(true); - pendingReadOp.initiate(); - PendingReadOp.SingleLedgerEntryRequest first = pendingReadOp.seq.get(0); - PendingReadOp.SingleLedgerEntryRequest second = pendingReadOp.seq.get(1); - - pendingReadOp.submitCallback(-105); - - // pendingReadOp.submitCallback(-105) will close all ledgerEntryImpl - assertEquals(-1, first.entryImpl.getEntryId()); - assertEquals(-1, first.entryImpl.getLedgerId()); - assertEquals(-1, first.entryImpl.getLength()); - assertNull(first.entryImpl.getEntryBuffer()); - assertTrue(first.complete.get()); - - assertEquals(-1, second.entryImpl.getEntryId()); - assertEquals(-1, second.entryImpl.getLedgerId()); - assertEquals(-1, second.entryImpl.getLength()); - assertNull(second.entryImpl.getEntryBuffer()); - assertTrue(second.complete.get()); - - // Mock ledgerEntryImpl reuse - ByteBuf byteBuf = Unpooled.buffer(10); - pendingReadOp.readEntryComplete(BKException.Code.OK, 1, 1, Unpooled.buffer(10), - new ReadOpBase.ReadContext(1, BookieId.parse("test"), first)); - - // byteBuf has been release - assertEquals(byteBuf.refCnt(), 1); - // entryBuffer is not replaced - assertNull(first.entryImpl.getEntryBuffer()); - // ledgerEntryRequest has been complete - assertTrue(first.complete.get()); - - pendingReadOp = new PendingReadOp(lh, clientContext, 1, 2, false); - pendingReadOp.parallelRead(true); - pendingReadOp.initiate(); - - // read entry failed twice, will not close twice - pendingReadOp.readEntryComplete(BKException.Code.TooManyRequestsException, 1, 1, Unpooled.buffer(10), - new ReadOpBase.ReadContext(1, BookieId.parse("test"), first)); - - pendingReadOp.readEntryComplete(BKException.Code.TooManyRequestsException, 1, 1, Unpooled.buffer(10), - new ReadOpBase.ReadContext(1, BookieId.parse("test"), first)); - - // will not complete twice when completed - byteBuf = Unpooled.buffer(10); - pendingReadOp.readEntryComplete(Code.OK, 1, 1, Unpooled.buffer(10), - new ReadOpBase.ReadContext(1, BookieId.parse("test"), first)); - assertEquals(1, byteBuf.refCnt()); - - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPendingReadLacOp.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPendingReadLacOp.java deleted file mode 100644 index a37462dee7d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPendingReadLacOp.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCounted; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.proto.MockBookieClient; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.ByteBufList; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests PendingReadLacOp internals. - */ -public class TestPendingReadLacOp extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestPendingReadLacOp.class); - byte[] pwd = "asdf".getBytes(); - byte[] data = "foo".getBytes(); - - public TestPendingReadLacOp() { - super(3); - } - - @Test - public void testPendingReadLacOpMissingExplicitLAC() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, 2, BookKeeper.DigestType.CRC32, pwd); - lh.append(data); - lh.append(data); - lh.append(data); - - final CompletableFuture result = new CompletableFuture<>(); - PendingReadLacOp pro = new PendingReadLacOp(lh, bkc.getBookieClient(), lh.getCurrentEnsemble(), - (rc, lac) -> result.complete(lac)) { - @Override - public void initiate() { - for (int i = 0; i < lh.getCurrentEnsemble().size(); i++) { - final int index = i; - ReferenceCounted toSend = lh.getDigestManager().computeDigestAndPackageForSending( - 2, - 1, - data.length, - Unpooled.wrappedBuffer(data), - new byte[20], - 0); - - bkc.scheduler.schedule(() -> { - readLacComplete( - 0, - lh.getId(), - null, - MockBookieClient.copyData(toSend), - index); - - }, 0, TimeUnit.SECONDS); - bookieClient.readLac(lh.getCurrentEnsemble().get(i), - lh.ledgerId, this, i); - } - } - }; - pro.initiate(); - assertEquals(1, result.get().longValue()); - } - - @Test - public void testPendingReadLacOpMissingLAC() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, 2, BookKeeper.DigestType.MAC, pwd); - lh.append(data); - lh.append(data); - lh.append(data); - - final CompletableFuture result = new CompletableFuture<>(); - PendingReadLacOp pro = new PendingReadLacOp(lh, bkc.getBookieClient(), lh.getCurrentEnsemble(), - (rc, lac) -> result.complete(lac)) { - @Override - public void initiate() { - for (int i = 0; i < lh.getCurrentEnsemble().size(); i++) { - final int index = i; - ByteBufList buffer = lh.getDigestManager().computeDigestAndPackageForSendingLac(1); - bkc.scheduler.schedule(() -> { - readLacComplete( - 0, - lh.getId(), - buffer.getBuffer(0), - null, - index); - }, 0, TimeUnit.SECONDS); - bookieClient.readLac(lh.getCurrentEnsemble().get(i), - lh.ledgerId, this, i); - } - } - }; - pro.initiate(); - assertEquals(result.get().longValue(), 1); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPiggybackLAC.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPiggybackLAC.java deleted file mode 100644 index 26a9e0611fe..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPiggybackLAC.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.SortedLedgerStorage; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test a piggyback LAC. - */ -@RunWith(Parameterized.class) -public class TestPiggybackLAC extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(TestPiggybackLAC.class); - - final DigestType digestType; - - public TestPiggybackLAC(Class storageClass) { - super(1); - this.digestType = DigestType.CRC32; - baseConf.setLedgerStorageClass(storageClass.getName()); - } - - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { - { InterleavedLedgerStorage.class }, - { SortedLedgerStorage.class }, - { DbLedgerStorage.class }, - }); - } - - @Test - public void testPiggybackLAC() throws Exception { - int numEntries = 10; - LedgerHandle lh = bkc.createLedger(1, 1, 1, digestType, "".getBytes()); - // tried to add entries - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + i).getBytes()); - LOG.info("Added entry {}.", i); - } - LedgerHandle readLh = bkc.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - long lastLAC = readLh.getLastAddConfirmed(); - assertEquals(numEntries - 2, lastLAC); - // write add entries - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + (i + numEntries)).getBytes()); - LOG.info("Added entry {}.", (i + numEntries)); - } - int numReads = 0; - int i = 0; - while (true) { - if (i > readLh.getLastAddConfirmed()) { - break; - } - Enumeration data = readLh.readEntries(i, i); - while (data.hasMoreElements()) { - LedgerEntry entry = data.nextElement(); - assertEquals("data" + i, new String(entry.getEntry())); - ++numReads; - } - i++; - } - assertEquals(2 * numEntries - 1, numReads); - assertEquals(2 * numEntries - 2, readLh.getLastAddConfirmed()); - readLh.close(); - lh.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicy.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicy.java deleted file mode 100644 index ed37159ee19..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicy.java +++ /dev/null @@ -1,3129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicyImpl.REPP_DNS_RESOLVER_CLASS; -import static org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicyImpl.shuffleWithMask; -import static org.apache.bookkeeper.client.RoundRobinDistributionSchedule.writeSetFromValues; -import static org.apache.bookkeeper.feature.SettableFeatureProvider.DISABLE_ALL; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.netty.util.HashedWheelTimer; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import junit.framework.TestCase; -import org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException; -import org.apache.bookkeeper.client.BookieInfoReader.BookieInfo; -import org.apache.bookkeeper.client.EnsemblePlacementPolicy.PlacementPolicyAdherence; -import org.apache.bookkeeper.client.ITopologyAwareEnsemblePlacementPolicy.Ensemble; -import org.apache.bookkeeper.client.TopologyAwareEnsemblePlacementPolicy.EnsembleForReplacementWithNoConstraints; -import org.apache.bookkeeper.client.TopologyAwareEnsemblePlacementPolicy.TruePredicate; -import org.apache.bookkeeper.common.util.ReflectionUtils; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.AbstractDNSToSwitchMapping; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieNode; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.bookkeeper.net.NetworkTopology; -import org.apache.bookkeeper.net.Node; -import org.apache.bookkeeper.net.ScriptBasedMapping; -import org.apache.bookkeeper.proto.BookieAddressResolver; -import org.apache.bookkeeper.stats.Gauge; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.tuple.Pair; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the rackaware ensemble placement policy. - */ -public class TestRackawareEnsemblePlacementPolicy extends TestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestRackawareEnsemblePlacementPolicy.class); - - RackawareEnsemblePlacementPolicy repp; - final List ensemble = new ArrayList(); - DistributionSchedule.WriteSet writeSet = DistributionSchedule.NULL_WRITE_SET; - ClientConfiguration conf = new ClientConfiguration(); - BookieSocketAddress addr1; - BookieSocketAddress addr2, addr3, addr4; - io.netty.util.HashedWheelTimer timer; - final int minNumRacksPerWriteQuorumConfValue = 2; - - @Override - protected void setUp() throws Exception { - super.setUp(); - StaticDNSResolver.reset(); - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostAddress(), - NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack("127.0.0.1", NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack("localhost", NetworkTopology.DEFAULT_REGION_AND_RACK); - LOG.info("Set up static DNS Resolver."); - conf.setProperty(REPP_DNS_RESOLVER_CLASS, StaticDNSResolver.class.getName()); - conf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - addr1 = new BookieSocketAddress("127.0.0.2", 3181); - addr2 = new BookieSocketAddress("127.0.0.3", 3181); - addr3 = new BookieSocketAddress("127.0.0.4", 3181); - addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION + "/rack1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), NetworkTopology.DEFAULT_REGION + "/rack2"); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - ensemble.add(addr4.toBookieId()); - writeSet = writeSetFromValues(0, 1, 2, 3); - - timer = new HashedWheelTimer( - new ThreadFactoryBuilder().setNameFormat("TestTimer-%d").build(), - conf.getTimeoutTimerTickDurationMs(), TimeUnit.MILLISECONDS, - conf.getTimeoutTimerNumTicks()); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - } - - @Override - protected void tearDown() throws Exception { - repp.uninitalize(); - super.tearDown(); - } - - static BookiesHealthInfo getBookiesHealthInfo() { - return getBookiesHealthInfo(new HashMap<>(), new HashMap<>()); - } - - static BookiesHealthInfo getBookiesHealthInfo(Map bookieFailureHistory, - Map bookiePendingRequests) { - return new BookiesHealthInfo() { - @Override - public long getBookieFailureHistory(BookieId bookieSocketAddress) { - return bookieFailureHistory.getOrDefault(bookieSocketAddress, -1L); - } - - @Override - public long getBookiePendingRequests(BookieId bookieSocketAddress) { - return bookiePendingRequests.getOrDefault(bookieSocketAddress, 0L); - } - }; - } - - static void updateMyRack(String rack) throws Exception { - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostAddress(), rack); - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostName(), rack); - StaticDNSResolver.addNodeToRack("127.0.0.1", rack); - StaticDNSResolver.addNodeToRack("localhost", rack); - } - - @Test - public void testInitalize() throws Exception{ - String dnsResolverName = conf.getString(REPP_DNS_RESOLVER_CLASS, ScriptBasedMapping.class.getName()); - DNSToSwitchMapping dnsResolver = ReflectionUtils.newInstance(dnsResolverName, DNSToSwitchMapping.class); - AbstractDNSToSwitchMapping tmp = (AbstractDNSToSwitchMapping) dnsResolver; - assertNull(tmp.getBookieAddressResolver()); - - dnsResolver.setBookieAddressResolver(repp.bookieAddressResolver); - assertNotNull(tmp.getBookieAddressResolver()); - } - - @Test - public void testNodeDown() throws Exception { - repp.uninitalize(); - updateMyRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), - writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(1, 2, 3, 0); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeReadOnly() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - Set ro = new HashSet(); - ro.add(addr1.toBookieId()); - repp.onClusterChanged(addrs, ro); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - LOG.info("reorder set : {}", reorderSet); - assertEquals(reorderSet, origWriteSet); - } - - @Test - public void testNodeSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - repp.registerSlowBookie(addr1.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); - repp.onClusterChanged(addrs, new HashSet<>()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(1, 2, 3, 0); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testTwoNodesSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - repp.registerSlowBookie(addr1.toBookieId(), 0L); - repp.registerSlowBookie(addr2.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); - bookiePendingMap.put(addr2.toBookieId(), 2L); - repp.onClusterChanged(addrs, new HashSet<>()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(2, 3, 0, 1); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testTwoNodesDown() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - addrs.remove(addr2.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(2, 3, 0, 1); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeDownAndReadOnly() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - addrs.remove(addr2.toBookieId()); - Set roAddrs = new HashSet(); - roAddrs.add(addr2.toBookieId()); - repp.onClusterChanged(addrs, roAddrs); - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(2, 3, 1, 0); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeDownAndNodeSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - repp.registerSlowBookie(addr1.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); - addrs.remove(addr2.toBookieId()); - repp.onClusterChanged(addrs, new HashSet<>()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(2, 3, 0, 1); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeDownAndReadOnlyAndNodeSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - addrs.remove(addr2.toBookieId()); - Set ro = new HashSet(); - ro.add(addr2.toBookieId()); - repp.registerSlowBookie(addr3.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr3.toBookieId(), 1L); - addrs.remove(addr2.toBookieId()); - repp.onClusterChanged(addrs, ro); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 1, 2, 0); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - /* - * Tests the reordering of the writeSet based on number of pending requests. - * Expect the third bookie to be placed first since its number of pending requests - * is READ_REORDER_THRESHOLD_PENDING_REQUESTS=10 less than the originally first bookie. - */ - @Test - public void testPendingRequestsReorder() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - ClientConfiguration conf = (ClientConfiguration) this.conf.clone(); - conf.setReorderThresholdPendingRequests(10); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 20L); - bookiePendingMap.put(addr2.toBookieId(), 7L); - bookiePendingMap.put(addr3.toBookieId(), 1L); // best bookie -> this one first - bookiePendingMap.put(addr4.toBookieId(), 5L); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(2, 0, 1, 3); - LOG.info("reorder set : {}", reorderSet); - assertEquals("expect bookie idx 2 first", expectedSet, reorderSet); - } - - /* - * Tests the reordering of the writeSet based on number of pending requests for - * an ensemble that is larger than the writeSet. - * Expect the sixth bookie to be placed first since its number of pending requests - * is READ_REORDER_THRESHOLD_PENDING_REQUESTS=10 less than the originally first bookie. - */ - @Test - public void testPendingRequestsReorderLargeEnsemble() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - ClientConfiguration conf = (ClientConfiguration) this.conf.clone(); - conf.setReorderThresholdPendingRequests(10); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); // not in write set - bookiePendingMap.put(addr2.toBookieId(), 20L); - bookiePendingMap.put(addr3.toBookieId(), 0L); // not in write set - bookiePendingMap.put(addr4.toBookieId(), 12L); - bookiePendingMap.put(addr5.toBookieId(), 9L); // not in write set - bookiePendingMap.put(addr6.toBookieId(), 2L); // best bookie -> this one first - bookiePendingMap.put(addr7.toBookieId(), 10L); - List ensemble = new ArrayList(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr5.toBookieId()); - ensemble.add(addr6.toBookieId()); - ensemble.add(addr7.toBookieId()); - - DistributionSchedule.WriteSet writeSet = writeSetFromValues(1, 3, 5, 6); - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(5, 1, 3, 6); - LOG.info("reorder set : {}", reorderSet); - assertEquals("expect bookie idx 5 first", expectedSet, reorderSet); - } - - /* - * Tests the reordering of the writeSet based on number of pending requests. - * Expect no reordering in this case since the currently first bookie's number of - * pending requests is less than READ_REORDER_THRESHOLD_PENDING_REQUESTS=10 lower - * than the best bookie. - */ - @Test - public void testPendingRequestsNoReorder1() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - ClientConfiguration conf = (ClientConfiguration) this.conf.clone(); - conf.setReorderThresholdPendingRequests(10); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 10L); // -> this one first - bookiePendingMap.put(addr2.toBookieId(), 7L); - bookiePendingMap.put(addr3.toBookieId(), 1L); // best bookie, but below threshold - bookiePendingMap.put(addr4.toBookieId(), 5L); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - LOG.info("reorder set : {}", reorderSet); - assertEquals("writeSet should be in original order", origWriteSet, reorderSet); - } - - /* - * Tests the reordering of the writeSet based on number of pending requests. - * Expect no reordering in this case since the currently first bookie's number of - * pending requests is lowest among all bookies already. - */ - @Test - public void testPendingRequestsNoReorder2() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RackawareEnsemblePlacementPolicy(); - ClientConfiguration conf = (ClientConfiguration) this.conf.clone(); - conf.setReorderThresholdPendingRequests(10); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); // -> this one first - bookiePendingMap.put(addr2.toBookieId(), 7L); - bookiePendingMap.put(addr3.toBookieId(), 1L); - bookiePendingMap.put(addr4.toBookieId(), 5L); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - LOG.info("reorder set : {}", reorderSet); - assertEquals("writeSet should be in original order", origWriteSet, reorderSet); - } - - @Test - public void testIsEnsembleAdheringToPlacementPolicy() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/default-region/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - List emptyEnsemble = new ArrayList<>(); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - repp.isEnsembleAdheringToPlacementPolicy(emptyEnsemble, 3, 3)); - - List ensemble = new ArrayList<>(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - repp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 3)); - - ensemble = new ArrayList<>(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - repp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 3)); - - ensemble = new ArrayList<>(); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr5.toBookieId()); - ensemble.add(addr6.toBookieId()); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - repp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 3)); - } - - @Test - public void testReplaceBookieWithEnoughBookiesInSameRack() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - EnsemblePlacementPolicy.PlacementResult replaceBookieResponse = - repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), addr2.toBookieId(), new HashSet<>()); - BookieId replacedBookie = replaceBookieResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = replaceBookieResponse.getAdheringToPolicy(); - assertEquals(addr3.toBookieId(), replacedBookie); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - } - - @Test - public void testReplaceBookieWithEnoughBookiesInDifferentRack() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r4"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - EnsemblePlacementPolicy.PlacementResult replaceBookieResponse = - repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), addr2.toBookieId(), excludedAddrs); - BookieId replacedBookie = replaceBookieResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = replaceBookieResponse.getAdheringToPolicy(); - assertFalse(addr1.toBookieId().equals(replacedBookie)); - assertTrue(addr3.toBookieId().equals(replacedBookie) || addr4.toBookieId().equals(replacedBookie)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - } - - @Test - public void testReplaceBookieWithNotEnoughBookies() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r4"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - excludedAddrs.add(addr3.toBookieId()); - excludedAddrs.add(addr4.toBookieId()); - try { - repp.replaceBookie(1, 1, 1, null, new ArrayList(), addr2.toBookieId(), excludedAddrs); - fail("Should throw BKNotEnoughBookiesException when there is not enough bookies"); - } catch (BKNotEnoughBookiesException bnebe) { - // should throw not enou - } - } - - @Test - public void testReplaceBookieWithEnoughBookiesInSameRackAsEnsemble() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - List ensembleBookies = new ArrayList(); - ensembleBookies.add(addr2.toBookieId()); - ensembleBookies.add(addr4.toBookieId()); - EnsemblePlacementPolicy.PlacementResult replaceBookieResponse = repp.replaceBookie( - 1, 1, 1 , null, - ensembleBookies, - addr4.toBookieId(), - new HashSet<>()); - BookieId replacedBookie = replaceBookieResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = replaceBookieResponse.getAdheringToPolicy(); - assertEquals(addr1.toBookieId(), replacedBookie); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - } - - @Test - public void testNewEnsembleWithSingleRack() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.9", 3181); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse; - ensembleResponse = repp.newEnsemble(3, 2, 2, null, new HashSet<>()); - List ensemble = ensembleResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals(0, getNumCoveredWriteQuorums(ensemble, 2, conf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.FAIL, isEnsembleAdheringToPlacementPolicy); - EnsemblePlacementPolicy.PlacementResult> ensembleResponse2; - ensembleResponse2 = repp.newEnsemble(4, 2, 2, null, new HashSet<>()); - List ensemble2 = ensembleResponse2.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy2 = ensembleResponse2.getAdheringToPolicy(); - assertEquals(0, getNumCoveredWriteQuorums(ensemble2, 2, conf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.FAIL, isEnsembleAdheringToPlacementPolicy); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testSingleRackWithEnforceMinNumRacks() throws Exception { - repp.uninitalize(); - updateMyRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(2); - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - List ensemble; - try { - ensemble = repp.newEnsemble(3, 2, 2, null, new HashSet<>()).getResult(); - fail("Should get not enough bookies exception since there is only one rack."); - } catch (BKNotEnoughBookiesException bnebe) { - } - - try { - ensemble = repp.newEnsemble(3, 2, 2, new HashSet<>(), - EnsembleForReplacementWithNoConstraints.INSTANCE, TruePredicate.INSTANCE).getResult(); - fail("Should get not enough bookies exception since there is only one rack."); - } catch (BKNotEnoughBookiesException bnebe) { - } - } - - @Test - public void testNewEnsembleWithEnforceMinNumRacks() throws Exception { - String defaultRackForThisTest = NetworkTopology.DEFAULT_REGION_AND_RACK; - repp.uninitalize(); - updateMyRack(defaultRackForThisTest); - - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(""); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, - DISABLE_ALL, statsLogger, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(defaultRackForThisTest); - Gauge numBookiesInDefaultRackGauge = statsLogger - .getGauge(BookKeeperClientStats.NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK); - - int numOfRacks = 3; - int numOfBookiesPerRack = 5; - BookieId[] bookieSocketAddresses = new BookieId[numOfRacks * numOfBookiesPerRack]; - - for (int i = 0; i < numOfRacks; i++) { - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieSocketAddresses[index] = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + index, "/default-region/r" + i); - } - } - - int numOfBookiesInDefaultRack = 5; - BookieId[] bookieSocketAddressesInDefaultRack = new BookieId[numOfBookiesInDefaultRack]; - for (int i = 0; i < numOfBookiesInDefaultRack; i++) { - bookieSocketAddressesInDefaultRack[i] = new BookieSocketAddress("128.0.0." + (100 + i), 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + (100 + i), - defaultRackForThisTest); - } - - List nonDefaultRackBookiesList = Arrays.asList(bookieSocketAddresses); - List defaultRackBookiesList = Arrays.asList(bookieSocketAddressesInDefaultRack); - Set writableBookies = new HashSet(nonDefaultRackBookiesList); - writableBookies.addAll(defaultRackBookiesList); - repp.onClusterChanged(writableBookies, new HashSet()); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", numOfBookiesInDefaultRack, - numBookiesInDefaultRackGauge.getSample()); - - try { - // this newEnsemble call will exclude default rack bookies - repp.newEnsemble(8, 4, 4, null, new HashSet<>()); - fail("Should get not enough bookies exception since there are only 3 non-default racks"); - } catch (BKNotEnoughBookiesException bnebe) { - } - - try { - repp.newEnsemble(8, 4, 4, new HashSet<>(defaultRackBookiesList), - EnsembleForReplacementWithNoConstraints.INSTANCE, TruePredicate.INSTANCE); - fail("Should get not enough bookies exception since there are only 3 non-default racks" - + " and defaultrack bookies are excluded"); - } catch (BKNotEnoughBookiesException bnebe) { - } - - /* - * Though minNumRacksPerWriteQuorum is set to 4, since writeQuorum is 3 - * and there are enough bookies in 3 racks, this newEnsemble calls - * should succeed. - */ - EnsemblePlacementPolicy.PlacementResult> ensembleResponse; - List ensemble; - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy; - int ensembleSize = numOfRacks * numOfBookiesPerRack; - int writeQuorumSize = numOfRacks; - int ackQuorumSize = numOfRacks; - - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, ackQuorumSize, null, new HashSet<>()); - ensemble = ensembleResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals("Number of writeQuorum sets covered", ensembleSize, - getNumCoveredWriteQuorums(ensemble, writeQuorumSize, clientConf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, ackQuorumSize, - new HashSet<>(defaultRackBookiesList), EnsembleForReplacementWithNoConstraints.INSTANCE, - TruePredicate.INSTANCE); - ensemble = ensembleResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals("Number of writeQuorum sets covered", ensembleSize, - getNumCoveredWriteQuorums(ensemble, writeQuorumSize, clientConf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - } - - @Test - public void testNewEnsembleWithSufficientRacksAndEnforceMinNumRacks() throws Exception { - repp.uninitalize(); - - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - int writeQuorumSize = 3; - int ackQuorumSize = 3; - int effectiveMinNumRacksPerWriteQuorum = Math.min(minNumRacksPerWriteQuorum, writeQuorumSize); - - int numOfRacks = 2 * effectiveMinNumRacksPerWriteQuorum - 1; - int numOfBookiesPerRack = 20; - BookieId[] bookieSocketAddresses = new BookieId[numOfRacks * numOfBookiesPerRack]; - - for (int i = 0; i < numOfRacks; i++) { - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieSocketAddresses[index] = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + index, "/default-region/r" + i); - } - } - - Set addrs = new HashSet(); - repp.onClusterChanged(new HashSet(Arrays.asList(bookieSocketAddresses)), - new HashSet()); - - /* - * in this scenario we have enough number of racks (2 * - * effectiveMinNumRacksPerWriteQuorum - 1) and more number of bookies in - * each rack. So we should be able to create ensemble for all - * ensembleSizes (as long as there are enough number of bookies in each - * rack). - */ - EnsemblePlacementPolicy.PlacementResult> ensembleResponse; - List ensemble; - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy; - for (int ensembleSize = effectiveMinNumRacksPerWriteQuorum; ensembleSize < 40; ensembleSize++) { - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, ackQuorumSize, null, new HashSet<>()); - ensemble = ensembleResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals("Number of writeQuorum sets covered", ensembleSize, - getNumCoveredWriteQuorums(ensemble, writeQuorumSize, clientConf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, ackQuorumSize, new HashSet<>(), - EnsembleForReplacementWithNoConstraints.INSTANCE, TruePredicate.INSTANCE); - ensemble = ensembleResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals("Number of writeQuorum sets covered", ensembleSize, - getNumCoveredWriteQuorums(ensemble, writeQuorumSize, clientConf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - } - } - - @Test - public void testReplaceBookieWithEnforceMinNumRacks() throws Exception { - String defaultRackForThisTest = NetworkTopology.DEFAULT_REGION_AND_RACK; - repp.uninitalize(); - updateMyRack(defaultRackForThisTest); - - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(""); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, DISABLE_ALL, - statsLogger, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(defaultRackForThisTest); - Gauge numBookiesInDefaultRackGauge = statsLogger - .getGauge(BookKeeperClientStats.NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK); - - int numOfRacks = 3; - int numOfBookiesPerRack = 5; - Set bookieSocketAddresses = new HashSet(); - Map bookieRackMap = new HashMap(); - BookieId bookieAddress; - String rack; - for (int i = 0; i < numOfRacks; i++) { - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieAddress = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - rack = "/default-region/r" + i; - StaticDNSResolver.addNodeToRack("128.0.0." + index, rack); - bookieSocketAddresses.add(bookieAddress); - bookieRackMap.put(bookieAddress, rack); - } - } - /* - * bookies in this default rack should not be returned for replacebookie - * response. - */ - int numOfBookiesInDefaultRack = 5; - BookieId[] bookieSocketAddressesInDefaultRack = new BookieId[numOfBookiesInDefaultRack]; - for (int i = 0; i < numOfBookiesInDefaultRack; i++) { - bookieSocketAddressesInDefaultRack[i] = new BookieSocketAddress("127.0.0." + (i + 100), 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("127.0.0." + (i + 100), - defaultRackForThisTest); - } - - Set nonDefaultRackBookiesList = bookieSocketAddresses; - List defaultRackBookiesList = Arrays.asList(bookieSocketAddressesInDefaultRack); - Set writableBookies = new HashSet(nonDefaultRackBookiesList); - writableBookies.addAll(defaultRackBookiesList); - repp.onClusterChanged(writableBookies, new HashSet()); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", numOfBookiesInDefaultRack, - numBookiesInDefaultRackGauge.getSample()); - - /* - * Though minNumRacksPerWriteQuorum is set to 4, since writeQuorum is 3 - * and there are enough bookies in 3 racks, this newEnsemble call should - * succeed. - */ - EnsemblePlacementPolicy.PlacementResult> ensembleResponse; - List ensemble; - int ensembleSize = numOfRacks * numOfBookiesPerRack; - int writeQuorumSize = numOfRacks; - int ackQuorumSize = numOfRacks; - - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, ackQuorumSize, null, new HashSet<>()); - ensemble = ensembleResponse.getResult(); - - BookieId bookieInEnsembleToBeReplaced = ensemble.get(7); - // get rack of some other bookie - String rackOfOtherBookieInEnsemble = bookieRackMap.get(ensemble.get(8)); - BookieSocketAddress newBookieAddress1 = new BookieSocketAddress("128.0.0.100", 3181); - /* - * add the newBookie to the rack of some other bookie in the current - * ensemble - */ - StaticDNSResolver.addNodeToRack(newBookieAddress1.getHostName(), rackOfOtherBookieInEnsemble); - bookieSocketAddresses.add(newBookieAddress1.toBookieId()); - writableBookies.add(newBookieAddress1.toBookieId()); - bookieRackMap.put(newBookieAddress1.toBookieId(), rackOfOtherBookieInEnsemble); - - repp.onClusterChanged(writableBookies, new HashSet()); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", numOfBookiesInDefaultRack, - numBookiesInDefaultRackGauge.getSample()); - try { - repp.replaceBookie(ensembleSize, writeQuorumSize, ackQuorumSize, null, - ensemble, bookieInEnsembleToBeReplaced, new HashSet<>()); - fail("Should get not enough bookies exception since there are no more bookies in rack" - + "of 'bookieInEnsembleToReplace'" - + "and new bookie added belongs to the rack of some other bookie in the ensemble"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - - String newRack = "/default-region/r100"; - BookieSocketAddress newBookieAddress2 = new BookieSocketAddress("128.0.0.101", 3181); - /* - * add the newBookie to a new rack. - */ - StaticDNSResolver.addNodeToRack(newBookieAddress2.getHostName(), newRack); - bookieSocketAddresses.add(newBookieAddress2.toBookieId()); - writableBookies.add(newBookieAddress2.toBookieId()); - bookieRackMap.put(newBookieAddress2.toBookieId(), newRack); - - repp.onClusterChanged(writableBookies, new HashSet()); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", numOfBookiesInDefaultRack, - numBookiesInDefaultRackGauge.getSample()); - /* - * this replaceBookie should succeed, because a new bookie is added to a - * new rack. - */ - EnsemblePlacementPolicy.PlacementResult replaceBookieResponse; - BookieId replacedBookieAddress; - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy; - replaceBookieResponse = repp.replaceBookie(ensembleSize, writeQuorumSize, ackQuorumSize, null, ensemble, - bookieInEnsembleToBeReplaced, new HashSet<>()); - replacedBookieAddress = replaceBookieResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = replaceBookieResponse.getAdheringToPolicy(); - assertEquals("It should be newBookieAddress2", newBookieAddress2.toBookieId(), replacedBookieAddress); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - - Set bookiesToExclude = new HashSet<>(); - bookiesToExclude.add(newBookieAddress2.toBookieId()); - repp.onClusterChanged(writableBookies, new HashSet()); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", numOfBookiesInDefaultRack, - numBookiesInDefaultRackGauge.getSample()); - try { - repp.replaceBookie(ensembleSize, writeQuorumSize, ackQuorumSize, null, ensemble, - bookieInEnsembleToBeReplaced, bookiesToExclude); - fail("Should get not enough bookies exception since the only available bookie to replace" - + "is added to excludedBookies list"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - - // get rack of the bookie to be replaced - String rackOfBookieToBeReplaced = bookieRackMap.get(bookieInEnsembleToBeReplaced); - BookieSocketAddress newBookieAddress3 = new BookieSocketAddress("128.0.0.102", 3181); - /* - * add the newBookie to rack of the bookie to be replaced. - */ - StaticDNSResolver.addNodeToRack(newBookieAddress3.getHostName(), rackOfBookieToBeReplaced); - bookieSocketAddresses.add(newBookieAddress3.toBookieId()); - writableBookies.add(newBookieAddress3.toBookieId()); - bookieRackMap.put(newBookieAddress3.toBookieId(), rackOfBookieToBeReplaced); - - repp.onClusterChanged(writableBookies, new HashSet()); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", numOfBookiesInDefaultRack, - numBookiesInDefaultRackGauge.getSample()); - /* - * here we have added new bookie to the rack of the bookie to be - * replaced, so we should be able to replacebookie though - * newBookieAddress2 is added to excluded bookies list. - */ - replaceBookieResponse = repp.replaceBookie(ensembleSize, writeQuorumSize, ackQuorumSize, null, - ensemble, bookieInEnsembleToBeReplaced, bookiesToExclude); - replacedBookieAddress = replaceBookieResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = replaceBookieResponse.getAdheringToPolicy(); - assertEquals("It should be newBookieAddress3", newBookieAddress3.toBookieId(), replacedBookieAddress); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - } - - @Test - public void testSelectBookieFromNetworkLoc() throws Exception { - repp.uninitalize(); - - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - int numOfRacks = 3; - int numOfBookiesPerRack = 5; - String[] rackLocationNames = new String[numOfRacks]; - List bookieSocketAddresses = new ArrayList(); - Map bookieRackMap = new HashMap(); - BookieId bookieAddress; - - for (int i = 0; i < numOfRacks; i++) { - rackLocationNames[i] = "/default-region/r" + i; - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieAddress = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + index, rackLocationNames[i]); - bookieSocketAddresses.add(bookieAddress); - bookieRackMap.put(bookieAddress, rackLocationNames[i]); - } - } - String nonExistingRackLocation = "/default-region/r25"; - - repp.onClusterChanged(new HashSet(bookieSocketAddresses), - new HashSet()); - - String rack = bookieRackMap.get(bookieSocketAddresses.get(0)); - BookieNode bookieNode = repp.selectFromNetworkLocation(rack, new HashSet(), TruePredicate.INSTANCE, - EnsembleForReplacementWithNoConstraints.INSTANCE, false); - String recRack = bookieNode.getNetworkLocation(); - assertEquals("Rack of node", rack, recRack); - - try { - repp.selectFromNetworkLocation(nonExistingRackLocation, new HashSet(), TruePredicate.INSTANCE, - EnsembleForReplacementWithNoConstraints.INSTANCE, false); - fail("Should get not enough bookies exception since there are no bookies in this rack"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - - // it should not fail, since fallback is set to true and it should pick - // some random one - repp.selectFromNetworkLocation(nonExistingRackLocation, new HashSet(), TruePredicate.INSTANCE, - EnsembleForReplacementWithNoConstraints.INSTANCE, true); - - Set excludeBookiesOfRackR0 = new HashSet(); - for (int i = 0; i < numOfBookiesPerRack; i++) { - excludeBookiesOfRackR0.add(bookieSocketAddresses.get(i)); - } - - Set excludeBookieNodesOfRackR0 = repp.convertBookiesToNodes(excludeBookiesOfRackR0); - try { - repp.selectFromNetworkLocation(bookieRackMap.get(bookieSocketAddresses.get(0)), excludeBookieNodesOfRackR0, - TruePredicate.INSTANCE, EnsembleForReplacementWithNoConstraints.INSTANCE, false); - fail("Should get not enough bookies exception since all the bookies in r0 are added to the exclusion list"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - - // not expected to get exception since fallback is set to true - bookieNode = repp.selectFromNetworkLocation(bookieRackMap.get(bookieSocketAddresses.get(0)), - excludeBookieNodesOfRackR0, TruePredicate.INSTANCE, EnsembleForReplacementWithNoConstraints.INSTANCE, - true); - assertTrue("BookieNode should not be from Rack /r0" + bookieNode.getNetworkLocation(), - rackLocationNames[1].equals(bookieNode.getNetworkLocation()) - || rackLocationNames[2].equals(bookieNode.getNetworkLocation())); - } - - @Test - public void testSelectBookieFromExcludingRacks() throws Exception { - repp.uninitalize(); - - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - int numOfRacks = 3; - int numOfBookiesPerRack = 5; - String[] rackLocationNames = new String[numOfRacks]; - List bookieSocketAddresses = new ArrayList(); - Map bookieRackMap = new HashMap(); - BookieId bookieAddress; - - for (int i = 0; i < numOfRacks; i++) { - rackLocationNames[i] = "/default-region/r" + i; - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieAddress = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + index, rackLocationNames[i]); - bookieSocketAddresses.add(bookieAddress); - bookieRackMap.put(bookieAddress, rackLocationNames[i]); - } - } - - repp.onClusterChanged(new HashSet(bookieSocketAddresses), - new HashSet()); - - Set excludeBookiesOfRackR0 = new HashSet(); - for (int i = 0; i < numOfBookiesPerRack; i++) { - excludeBookiesOfRackR0.add(bookieSocketAddresses.get(i)); - } - - Set excludeBookieNodesOfRackR0 = repp.convertBookiesToNodes(excludeBookiesOfRackR0); - - Set excludeRacksRackR1AndR2 = new HashSet(); - excludeRacksRackR1AndR2.add(rackLocationNames[1]); - excludeRacksRackR1AndR2.add(rackLocationNames[2]); - - try { - repp.selectFromNetworkLocation(excludeRacksRackR1AndR2, excludeBookieNodesOfRackR0, TruePredicate.INSTANCE, - EnsembleForReplacementWithNoConstraints.INSTANCE, false); - fail("Should get not enough bookies exception racks R1 and R2 are" - + "excluded and all the bookies in r0 are added to the exclusion list"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - - BookieNode bookieNode = repp.selectFromNetworkLocation(excludeRacksRackR1AndR2, new HashSet(), - TruePredicate.INSTANCE, EnsembleForReplacementWithNoConstraints.INSTANCE, false); - assertTrue("BookieNode should be from Rack /r0" + bookieNode.getNetworkLocation(), - rackLocationNames[0].equals(bookieNode.getNetworkLocation())); - - // not expected to get exception since fallback is set to true - bookieNode = repp.selectFromNetworkLocation(excludeRacksRackR1AndR2, excludeBookieNodesOfRackR0, - TruePredicate.INSTANCE, EnsembleForReplacementWithNoConstraints.INSTANCE, true); - assertTrue("BookieNode should not be from Rack /r0" + bookieNode.getNetworkLocation(), - rackLocationNames[1].equals(bookieNode.getNetworkLocation()) - || rackLocationNames[2].equals(bookieNode.getNetworkLocation())); - } - - @Test - public void testSelectBookieFromNetworkLocAndExcludingRacks() throws Exception { - repp.uninitalize(); - - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - int numOfRacks = 3; - int numOfBookiesPerRack = 5; - String[] rackLocationNames = new String[numOfRacks]; - List bookieSocketAddresses = new ArrayList(); - Map bookieRackMap = new HashMap(); - BookieId bookieAddress; - - for (int i = 0; i < numOfRacks; i++) { - rackLocationNames[i] = "/default-region/r" + i; - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieAddress = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + index, rackLocationNames[i]); - bookieSocketAddresses.add(bookieAddress); - bookieRackMap.put(bookieAddress, rackLocationNames[i]); - } - } - String nonExistingRackLocation = "/default-region/r25"; - - repp.onClusterChanged(new HashSet(bookieSocketAddresses), - new HashSet()); - - Set excludeBookiesOfRackR0 = new HashSet(); - for (int i = 0; i < numOfBookiesPerRack; i++) { - excludeBookiesOfRackR0.add(bookieSocketAddresses.get(i)); - } - - Set excludeBookieNodesOfRackR0 = repp.convertBookiesToNodes(excludeBookiesOfRackR0); - - Set excludeRacksRackR1AndR2 = new HashSet(); - excludeRacksRackR1AndR2.add(rackLocationNames[1]); - excludeRacksRackR1AndR2.add(rackLocationNames[2]); - - try { - repp.selectFromNetworkLocation(nonExistingRackLocation, excludeRacksRackR1AndR2, - excludeBookieNodesOfRackR0, - TruePredicate.INSTANCE, EnsembleForReplacementWithNoConstraints.INSTANCE, false); - fail("Should get not enough bookies exception racks R1 and R2 are excluded and all the bookies in" - + "r0 are added to the exclusion list"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - - BookieNode bookieNode = repp.selectFromNetworkLocation(rackLocationNames[0], excludeRacksRackR1AndR2, - new HashSet(), TruePredicate.INSTANCE, EnsembleForReplacementWithNoConstraints.INSTANCE, false); - assertTrue("BookieNode should be from Rack /r0" + bookieNode.getNetworkLocation(), - rackLocationNames[0].equals(bookieNode.getNetworkLocation())); - - bookieNode = repp.selectFromNetworkLocation(rackLocationNames[0], new HashSet(), - excludeBookieNodesOfRackR0, TruePredicate.INSTANCE, - EnsembleForReplacementWithNoConstraints.INSTANCE, false); - assertTrue("BookieNode should not be from Rack /r0" + bookieNode.getNetworkLocation(), - rackLocationNames[1].equals(bookieNode.getNetworkLocation()) - || rackLocationNames[2].equals(bookieNode.getNetworkLocation())); - - bookieNode = repp.selectFromNetworkLocation(nonExistingRackLocation, excludeRacksRackR1AndR2, - excludeBookieNodesOfRackR0, TruePredicate.INSTANCE, EnsembleForReplacementWithNoConstraints.INSTANCE, - true); - assertTrue("BookieNode should not be from Rack /r0" + bookieNode.getNetworkLocation(), - rackLocationNames[1].equals(bookieNode.getNetworkLocation()) - || rackLocationNames[2].equals(bookieNode.getNetworkLocation())); - } - - @Test - public void testSelectBookieByExcludingRacksAndBookies() throws Exception { - repp.uninitalize(); - - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - /* - * Durability is enforced - * - * When durability is being enforced; we must not violate the predicate - * even when selecting a random bookie; as durability guarantee is not - * best effort; correctness is implied by it - */ - repp = new RackawareEnsemblePlacementPolicy(true); - repp.initialize(clientConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - int numOfRacks = 3; - int numOfBookiesPerRack = 5; - String[] rackLocationNames = new String[numOfRacks]; - List bookieSocketAddresses = new ArrayList(); - Map bookieRackMap = new HashMap(); - BookieId bookieAddress; - - for (int i = 0; i < numOfRacks; i++) { - rackLocationNames[i] = "/default-region/r" + i; - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieAddress = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + index, rackLocationNames[i]); - bookieSocketAddresses.add(bookieAddress); - bookieRackMap.put(bookieAddress, rackLocationNames[i]); - } - } - - repp.onClusterChanged(new HashSet(bookieSocketAddresses), - new HashSet()); - - Set excludeBookiesOfRackR0 = new HashSet(); - for (int i = 0; i < numOfBookiesPerRack; i++) { - excludeBookiesOfRackR0.add(bookieSocketAddresses.get(i)); - } - - Set excludeBookieNodesOfRackR0 = repp.convertBookiesToNodes(excludeBookiesOfRackR0); - - Set excludeRackR1 = new HashSet(); - excludeRackR1.add(rackLocationNames[1]); - - BookieNode nodeSelected; - nodeSelected = repp.selectFromNetworkLocation(excludeRackR1, excludeBookieNodesOfRackR0, TruePredicate.INSTANCE, - EnsembleForReplacementWithNoConstraints.INSTANCE, false); - assertEquals("BookieNode should be from Rack2", rackLocationNames[2], nodeSelected.getNetworkLocation()); - - try { - /* - * durability is enforced, so false predicate will reject all - * bookies. - */ - repp.selectFromNetworkLocation(excludeRackR1, excludeBookieNodesOfRackR0, (candidate, chosenBookies) -> { - return false; - }, EnsembleForReplacementWithNoConstraints.INSTANCE, false); - fail("Should get not enough bookies exception since we are using false predicate"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - - try { - /* - * Using ensemble which rejects all the nodes. - */ - repp.selectFromNetworkLocation(excludeRackR1, excludeBookieNodesOfRackR0, TruePredicate.INSTANCE, - new Ensemble() { - - @Override - public boolean addNode(BookieNode node) { - return false; - } - - @Override - public List toList() { - return null; - } - - @Override - public boolean validate() { - return false; - } - }, false); - fail("Should get not enough bookies exception since ensemble rejects all the nodes"); - } catch (BKNotEnoughBookiesException bnebe) { - // this is expected - } - } - - @Test - public void testNewEnsembleWithMultipleRacks() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r2"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - int ensembleSize = 3; - int writeQuorumSize = 2; - int acqQuorumSize = 2; - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - acqQuorumSize, null, new HashSet<>()); - List ensemble = ensembleResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - int numCovered = getNumCoveredWriteQuorums(ensemble, writeQuorumSize, - conf.getMinNumRacksPerWriteQuorum(), repp.bookieAddressResolver); - assertTrue(numCovered >= 1 && numCovered < 3); - assertEquals(PlacementPolicyAdherence.FAIL, isEnsembleAdheringToPlacementPolicy); - ensembleSize = 4; - EnsemblePlacementPolicy.PlacementResult> ensembleResponse2 = - repp.newEnsemble(ensembleSize, writeQuorumSize, - acqQuorumSize, null, new HashSet<>()); - List ensemble2 = ensembleResponse2.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy2 = ensembleResponse2.getAdheringToPolicy(); - numCovered = getNumCoveredWriteQuorums(ensemble2, writeQuorumSize, - conf.getMinNumRacksPerWriteQuorum(), repp.bookieAddressResolver); - assertTrue(numCovered >= 1 && numCovered < 3); - assertEquals(PlacementPolicyAdherence.FAIL, isEnsembleAdheringToPlacementPolicy2); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - //see: https://github.com/apache/bookkeeper/issues/3722 - @Test - public void testNewEnsembleWithMultipleRacksWithCommonRack() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - clientConf.setMinNumRacksPerWriteQuorum(3); - repp.uninitalize(); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.10", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/default-region/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - addrs.add(addr10.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - try { - int ensembleSize = 10; - int writeQuorumSize = 10; - int ackQuorumSize = 2; - - for (int i = 0; i < 50; ++i) { - Set excludeBookies = new HashSet<>(); - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - } - } catch (Exception e) { - fail("Can not new ensemble selection succeed"); - } - } - - @Test - public void testNewEnsembleWithMultipleRacksWithCommonRackFailed() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - clientConf.setMinNumRacksPerWriteQuorum(3); - repp.uninitalize(); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.10", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/default-region/r2"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - addrs.add(addr10.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - try { - int ensembleSize = 10; - int writeQuorumSize = 10; - int ackQuorumSize = 2; - - Set excludeBookies = new HashSet<>(); - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - fail("Can not new ensemble selection succeed"); - } catch (Exception e) { - assertTrue(e instanceof BKNotEnoughBookiesException); - } - } - - @Test - public void testNewEnsembleWithPickDifferentRack() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - int ensembleSize = 3; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - - Set excludeBookies = new HashSet<>(); - - for (int i = 0; i < 50; ++i) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - if (ensemble.contains(addr1.toBookieId()) && ensemble.contains(addr2.toBookieId())) { - fail("addr1 and addr2 is same rack."); - } - } - - //addr4 shutdown. - addrs.remove(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - for (int i = 0; i < 50; ++i) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - assertTrue(ensemble.contains(addr1.toBookieId()) && ensemble.contains(addr2.toBookieId())); - } - } - - @Test - public void testNewEnsemblePickLocalRackBookiesByHostname() throws Exception { - testNewEnsemblePickLocalRackBookiesInternal(true); - } - - @Test - public void testNewEnsemblePickLocalRackBookiesByIP() throws Exception { - testNewEnsemblePickLocalRackBookiesInternal(false); - } - - public void testNewEnsemblePickLocalRackBookiesInternal(boolean useHostnameResolveLocalNodePlacementPolicy) - throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.7", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/default-region/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/default-region/r4"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/default-region/r5"); - - String hostname = useHostnameResolveLocalNodePlacementPolicy - ? InetAddress.getLocalHost().getCanonicalHostName() : InetAddress.getLocalHost().getHostAddress(); - StaticDNSResolver.addNodeToRack(hostname, "/default-region/r1"); - if (useHostnameResolveLocalNodePlacementPolicy) { - conf.setUseHostnameResolveLocalNodePlacementPolicy(useHostnameResolveLocalNodePlacementPolicy); - } - - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - int ensembleSize = 3; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - - Set excludeBookies = new HashSet<>(); - - for (int i = 0; i < 50000; ++i) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - if (!ensemble.contains(addr1.toBookieId())) { - fail("Failed to select bookie located on the same rack with bookie client"); - } - if (ensemble.contains(addr2.toBookieId()) && ensemble.contains(addr3.toBookieId())) { - fail("addr2 and addr3 is same rack."); - } - } - - //addr4 shutdown. - addrs.remove(addr5.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - for (int i = 0; i < 50000; ++i) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - if (!ensemble.contains(addr1.toBookieId())) { - fail("Failed to select bookie located on the same rack with bookie client"); - } - } - - } - - @Test - public void testMinNumRacksPerWriteQuorumOfRacks() throws Exception { - int numOfRacksToCreate = 6; - int numOfNodesInEachRack = 5; - - // Update cluster - Set addrs = new HashSet(); - BookieId addr; - for (int i = 0; i < numOfRacksToCreate; i++) { - for (int j = 0; j < numOfNodesInEachRack; j++) { - addr = new BookieSocketAddress("128.0.0." + ((i * numOfNodesInEachRack) + j), 3181).toBookieId(); - // update dns mapping - StaticDNSResolver.addNodeToRack("128.0.0." + ((i * numOfNodesInEachRack) + j), "/default-region/r" + i); - addrs.add(addr); - } - } - - try { - ClientConfiguration newConf = new ClientConfiguration(conf); - // set MinNumRacksPerWriteQuorum to 4 - int minNumRacksPerWriteQuorum = 4; - int ensembleSize = 12; - int writeQuorumSize = 6; - validateNumOfWriteQuorumsCoveredInEnsembleCreation(addrs, minNumRacksPerWriteQuorum, ensembleSize, - writeQuorumSize); - - // set MinNumRacksPerWriteQuorum to 6 - newConf = new ClientConfiguration(conf); - minNumRacksPerWriteQuorum = 6; - ensembleSize = 6; - writeQuorumSize = 6; - validateNumOfWriteQuorumsCoveredInEnsembleCreation(addrs, minNumRacksPerWriteQuorum, ensembleSize, - writeQuorumSize); - - // set MinNumRacksPerWriteQuorum to 6 - newConf = new ClientConfiguration(conf); - minNumRacksPerWriteQuorum = 6; - ensembleSize = 10; - writeQuorumSize = ensembleSize; - validateNumOfWriteQuorumsCoveredInEnsembleCreation(addrs, minNumRacksPerWriteQuorum, ensembleSize, - writeQuorumSize); - - // set MinNumRacksPerWriteQuorum to 5 - newConf = new ClientConfiguration(conf); - minNumRacksPerWriteQuorum = 5; - ensembleSize = 24; - writeQuorumSize = 12; - validateNumOfWriteQuorumsCoveredInEnsembleCreation(addrs, minNumRacksPerWriteQuorum, ensembleSize, - writeQuorumSize); - - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - void validateNumOfWriteQuorumsCoveredInEnsembleCreation(Set addrs, - int minNumRacksPerWriteQuorum, int ensembleSize, int writeQuorumSize) throws Exception { - ClientConfiguration newConf = new ClientConfiguration(conf); - newConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(newConf, Optional. empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - repp.onClusterChanged(addrs, new HashSet()); - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - writeQuorumSize, null, new HashSet<>()); - List ensemble = ensembleResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - int numCovered = getNumCoveredWriteQuorums(ensemble, writeQuorumSize, - minNumRacksPerWriteQuorum, repp.bookieAddressResolver); - assertEquals("minimum number of racks covered for writequorum ensemble: " + ensemble, ensembleSize, numCovered); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - } - - @Test - public void testNewEnsembleWithEnoughRacks() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/default-region/r4"); - int availableNumOfRacks = 4; - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - int ensembleSize = 3; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, new HashSet<>()); - List ensemble1 = ensembleResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy1 = ensembleResponse.getAdheringToPolicy(); - assertEquals(ensembleSize, - getNumCoveredWriteQuorums(ensemble1, writeQuorumSize, conf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy1); - ensembleSize = 4; - writeQuorumSize = 4; - EnsemblePlacementPolicy.PlacementResult> ensembleResponse2 = - repp.newEnsemble(ensembleSize, writeQuorumSize, 2, null, new HashSet<>()); - List ensemble2 = ensembleResponse2.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy2 = ensembleResponse2.getAdheringToPolicy(); - assertEquals(ensembleSize, - getNumCoveredWriteQuorums(ensemble2, writeQuorumSize, conf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy2); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - /** - * Test for BOOKKEEPER-633. - */ - @Test - public void testRemoveBookieFromCluster() { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - } - - @Test - public void testWeightedPlacementAndReplaceBookieWithEnoughBookiesInSameRack() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - - int multiple = 10; - conf.setDiskWeightBasedPlacementEnabled(true); - conf.setBookieMaxWeightMultipleForWeightBasedPlacement(-1); // no max cap on weight - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet()); - Map bookieInfoMap = new HashMap(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(multiple * 100L, multiple * 100L)); - repp.updateBookieInfo(bookieInfoMap); - - Map selectionCounts = new HashMap(); - selectionCounts.put(addr3.toBookieId(), 0L); - selectionCounts.put(addr4.toBookieId(), 0L); - int numTries = 50000; - EnsemblePlacementPolicy.PlacementResult replaceBookieResponse; - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy; - BookieId replacedBookie; - for (int i = 0; i < numTries; i++) { - // replace node under r2 - replaceBookieResponse = repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), - addr2.toBookieId(), new HashSet<>()); - replacedBookie = replaceBookieResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = replaceBookieResponse.getAdheringToPolicy(); - assertTrue("replaced : " + replacedBookie, addr3.toBookieId().equals(replacedBookie) - || addr4.toBookieId().equals(replacedBookie)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - selectionCounts.put(replacedBookie, selectionCounts.get(replacedBookie) + 1); - } - double observedMultiple = ((double) selectionCounts.get(addr4.toBookieId()) - / (double) selectionCounts.get(addr3.toBookieId())); - assertTrue("Weights not being honored " + observedMultiple, Math.abs(observedMultiple - multiple) < 1); - } - - @Test - public void testWeightedPlacementAndReplaceBookieWithoutEnoughBookiesInSameRack() throws Exception { - BookieSocketAddress addr0 = new BookieSocketAddress("126.0.0.1", 3181); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - // update dns mapping - StaticDNSResolver.reset(); - StaticDNSResolver.addNodeToRack(addr0.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r0"); - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r3"); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r4"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr0.toBookieId()); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - - int multiple = 10, maxMultiple = 4; - conf.setDiskWeightBasedPlacementEnabled(true); - conf.setBookieMaxWeightMultipleForWeightBasedPlacement(maxMultiple); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet()); - Map bookieInfoMap = new HashMap(); - bookieInfoMap.put(addr0.toBookieId(), new BookieInfo(50L, 50L)); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(200L, 200L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(multiple * 50L, multiple * 50L)); - repp.updateBookieInfo(bookieInfoMap); - - Map selectionCounts = new HashMap(); - selectionCounts.put(addr0.toBookieId(), 0L); - selectionCounts.put(addr1.toBookieId(), 0L); - selectionCounts.put(addr2.toBookieId(), 0L); - selectionCounts.put(addr3.toBookieId(), 0L); - selectionCounts.put(addr4.toBookieId(), 0L); - int numTries = 50000; - EnsemblePlacementPolicy.PlacementResult replaceBookieResponse; - BookieId replacedBookie; - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy; - for (int i = 0; i < numTries; i++) { - // addr2 is on /r2 and this is the only one on this rack. So the replacement - // will come from other racks. However, the weight should be honored in such - // selections as well - replaceBookieResponse = repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), - addr2.toBookieId(), new HashSet<>()); - replacedBookie = replaceBookieResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = replaceBookieResponse.getAdheringToPolicy(); - assertTrue(addr0.toBookieId().equals(replacedBookie) - || addr1.toBookieId().equals(replacedBookie) - || addr3.toBookieId().equals(replacedBookie) - || addr4.toBookieId().equals(replacedBookie)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - selectionCounts.put(replacedBookie, selectionCounts.get(replacedBookie) + 1); - } - /* - * since addr2 has to be replaced, the remaining bookies weight are - 50, 100, 200, 500 (10*50) - * So the median calculated by WeightedRandomSelection is (100 + 200) / 2 = 150 - */ - double medianWeight = 150; - double medianSelectionCounts = (double) (medianWeight / bookieInfoMap.get(addr1.toBookieId()).getWeight()) - * selectionCounts.get(addr1.toBookieId()); - double observedMultiple1 = ((double) selectionCounts.get(addr4.toBookieId()) - / (double) medianSelectionCounts); - double observedMultiple2 = ((double) selectionCounts.get(addr4.toBookieId()) - / (double) selectionCounts.get(addr3.toBookieId())); - LOG.info("oM1 " + observedMultiple1 + " oM2 " + observedMultiple2); - assertTrue("Weights not being honored expected " + maxMultiple + " observed " + observedMultiple1, - Math.abs(observedMultiple1 - maxMultiple) < 1); - // expected multiple for addr3 - double expected = (medianWeight * maxMultiple) / bookieInfoMap.get(addr3.toBookieId()).getWeight(); - assertTrue("Weights not being honored expected " + expected + " observed " + observedMultiple2, - Math.abs(observedMultiple2 - expected) < 1); - } - - @Test - public void testWeightedPlacementAndNewEnsembleWithEnoughBookiesInSameRack() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.9", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr5.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr6.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r3"); - StaticDNSResolver.addNodeToRack(addr7.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r3"); - StaticDNSResolver.addNodeToRack(addr8.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r3"); - StaticDNSResolver.addNodeToRack(addr9.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r3"); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - - int maxMultiple = 4; - conf.setDiskWeightBasedPlacementEnabled(true); - conf.setBookieMaxWeightMultipleForWeightBasedPlacement(maxMultiple); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet()); - Map bookieInfoMap = new HashMap(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr5.toBookieId(), new BookieInfo(1000L, 1000L)); - bookieInfoMap.put(addr6.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr7.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr8.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr9.toBookieId(), new BookieInfo(1000L, 1000L)); - - repp.updateBookieInfo(bookieInfoMap); - - Map selectionCounts = new HashMap(); - for (BookieId b : addrs) { - selectionCounts.put(b, 0L); - } - int numTries = 10000; - - Set excludeList = new HashSet(); - EnsemblePlacementPolicy.PlacementResult> ensembleResponse; - List ensemble; - int ensembleSize = 3; - int writeQuorumSize = 2; - int acqQuorumSize = 2; - for (int i = 0; i < numTries; i++) { - // addr2 is on /r2 and this is the only one on this rack. So the replacement - // will come from other racks. However, the weight should be honored in such - // selections as well - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, acqQuorumSize, null, excludeList); - ensemble = ensembleResponse.getResult(); - assertTrue( - "Rackaware selection not happening " - + getNumCoveredWriteQuorums(ensemble, writeQuorumSize, - conf.getMinNumRacksPerWriteQuorum(), repp.bookieAddressResolver), - getNumCoveredWriteQuorums(ensemble, writeQuorumSize, - conf.getMinNumRacksPerWriteQuorum(), repp.bookieAddressResolver) >= 2); - for (BookieId b : ensemble) { - selectionCounts.put(b, selectionCounts.get(b) + 1); - } - } - - // the median weight used is 100 since addr2 and addr6 have the same weight, we use their - // selection counts as the same as median - double observedMultiple1 = ((double) selectionCounts.get(addr5.toBookieId()) - / (double) selectionCounts.get(addr2.toBookieId())); - double observedMultiple2 = ((double) selectionCounts.get(addr9.toBookieId()) - / (double) selectionCounts.get(addr6.toBookieId())); - assertTrue("Weights not being honored expected 2 observed " + observedMultiple1, - Math.abs(observedMultiple1 - maxMultiple) < 0.5); - assertTrue("Weights not being honored expected 4 observed " + observedMultiple2, - Math.abs(observedMultiple2 - maxMultiple) < 0.5); - } - - @Test - public void testWeightedPlacementAndNewEnsembleWithoutEnoughBookies() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r2"); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r3"); - StaticDNSResolver.addNodeToRack(addr5.getSocketAddress().getAddress().getHostAddress(), - NetworkTopology.DEFAULT_REGION + "/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - - int maxMultiple = 4; - conf.setDiskWeightBasedPlacementEnabled(true); - conf.setBookieMaxWeightMultipleForWeightBasedPlacement(maxMultiple); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet()); - Map bookieInfoMap = new HashMap(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(1000L, 1000L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr5.toBookieId(), new BookieInfo(1000L, 1000L)); - - repp.updateBookieInfo(bookieInfoMap); - EnsemblePlacementPolicy.PlacementResult> ensembleResponse; - List ensemble; - Set excludeList = new HashSet(); - try { - excludeList.add(addr1.toBookieId()); - excludeList.add(addr2.toBookieId()); - excludeList.add(addr3.toBookieId()); - excludeList.add(addr4.toBookieId()); - ensembleResponse = repp.newEnsemble(3, 2, 2, null, excludeList); - ensemble = ensembleResponse.getResult(); - fail("Should throw BKNotEnoughBookiesException when there is not enough bookies" + ensemble); - } catch (BKNotEnoughBookiesException e) { - // this is expected - } - try { - ensembleResponse = repp.newEnsemble(1, 1, 1, null, excludeList); - ensemble = ensembleResponse.getResult(); - } catch (BKNotEnoughBookiesException e) { - fail("Should not throw BKNotEnoughBookiesException when there are enough bookies for the ensemble"); - } - } - - static int getNumCoveredWriteQuorums(List ensemble, int writeQuorumSize, - int minNumRacksPerWriteQuorumConfValue, BookieAddressResolver bookieAddressResolver) throws Exception { - int ensembleSize = ensemble.size(); - int numCoveredWriteQuorums = 0; - for (int i = 0; i < ensembleSize; i++) { - Set racks = new HashSet(); - for (int j = 0; j < writeQuorumSize; j++) { - int bookieIdx = (i + j) % ensembleSize; - BookieId addr = ensemble.get(bookieIdx); - racks.add(StaticDNSResolver.getRack(bookieAddressResolver.resolve(addr).getHostName())); - } - int numOfRacksToCoverTo = Math.max(Math.min(writeQuorumSize, minNumRacksPerWriteQuorumConfValue), 2); - numCoveredWriteQuorums += (racks.size() >= numOfRacksToCoverTo ? 1 : 0); - } - return numCoveredWriteQuorums; - } - - @Test - public void testNodeWithFailures() throws Exception { - repp.uninitalize(); - updateMyRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - HashMap bookieFailures = new HashMap(); - - bookieFailures.put(addr1.toBookieId(), 20L); - bookieFailures.put(addr2.toBookieId(), 22L); - - // remove failure bookies: addr1 and addr2 - addrs = new HashSet(); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - DistributionSchedule.WriteSet reoderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(bookieFailures, new HashMap<>()), writeSet); - LOG.info("reorder set : {}", reoderSet); - assertEquals(ensemble.get(reoderSet.get(2)), addr1.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(3)), addr2.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(0)), addr3.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(1)), addr4.toBookieId()); - } - - @Test - public void testPlacementOnStabilizeNetworkTopology() throws Exception { - repp.uninitalize(); - updateMyRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp = new RackawareEnsemblePlacementPolicy(); - ClientConfiguration confLocal = new ClientConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setNetworkTopologyStabilizePeriodSeconds(99999); - repp.initialize(confLocal, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // addr4 left - addrs.remove(addr4.toBookieId()); - Set deadBookies = repp.onClusterChanged(addrs, new HashSet()); - assertTrue(deadBookies.isEmpty()); - - // we will never use addr4 even it is in the stabilized network topology - for (int i = 0; i < 5; i++) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(3, 2, 2, null, new HashSet()); - List ensemble = ensembleResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertFalse(ensemble.contains(addr4.toBookieId())); - assertEquals(PlacementPolicyAdherence.FAIL, isEnsembleAdheringToPlacementPolicy); - } - - // we could still use addr4 for urgent allocation if it is just bookie flapping - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(4, 2, 2, null, new HashSet()); - List ensemble = ensembleResponse.getResult(); - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals(PlacementPolicyAdherence.FAIL, isEnsembleAdheringToPlacementPolicy); - assertTrue(ensemble.contains(addr4.toBookieId())); - } - - @Test - public void testShuffleWithMask() { - int mask = 0xE1 << 16; - int maskBits = 0xFF << 16; - boolean shuffleOccurred = false; - - for (int i = 0; i < 100; i++) { - DistributionSchedule.WriteSet w = writeSetFromValues( - 1, 2, 3 & mask, 4 & mask, 5 & mask, 6); - shuffleWithMask(w, mask, maskBits); - assertEquals(w.get(0), 1); - assertEquals(w.get(1), 2); - assertEquals(w.get(5), 6); - - if (w.get(3) == (3 & mask) - || w.get(4) == (3 & mask)) { - shuffleOccurred = true; - } else if (w.get(2) != (3 & mask)) { - fail("3 not found"); - } - - if (w.get(2) == (4 & mask) - || w.get(4) == (4 & mask)) { - shuffleOccurred = true; - } else if (w.get(3) != (4 & mask)) { - fail("4 not found"); - } - - if (w.get(2) == (5 & mask) - || w.get(3) == (5 & mask)) { - shuffleOccurred = true; - } else if (w.get(4) != (5 & mask)) { - fail("5 not found"); - } - } - assertTrue(shuffleOccurred); - - // at start of array - shuffleOccurred = false; - for (int i = 0; i < 100; i++) { - DistributionSchedule.WriteSet w = writeSetFromValues( - 1 & mask, 2 & mask, 3 & mask, 4, 5, 6); - shuffleWithMask(w, mask, maskBits); - assertEquals(w.get(3), 4); - assertEquals(w.get(4), 5); - assertEquals(w.get(5), 6); - - if (w.get(1) == (1 & mask) - || w.get(2) == (1 & mask)) { - shuffleOccurred = true; - } else if (w.get(0) != (1 & mask)) { - fail("1 not found"); - } - - if (w.get(0) == (2 & mask) - || w.get(2) == (2 & mask)) { - shuffleOccurred = true; - } else if (w.get(1) != (2 & mask)) { - fail("2 not found"); - } - - if (w.get(0) == (3 & mask) - || w.get(1) == (3 & mask)) { - shuffleOccurred = true; - } else if (w.get(2) != (3 & mask)) { - fail("3 not found"); - } - } - assertTrue(shuffleOccurred); - - // at end of array - shuffleOccurred = false; - for (int i = 0; i < 100; i++) { - DistributionSchedule.WriteSet w = writeSetFromValues( - 1, 2, 3, 4 & mask, 5 & mask, 6 & mask); - shuffleWithMask(w, mask, maskBits); - assertEquals(w.get(0), 1); - assertEquals(w.get(1), 2); - assertEquals(w.get(2), 3); - - if (w.get(4) == (4 & mask) - || w.get(5) == (4 & mask)) { - shuffleOccurred = true; - } else if (w.get(3) != (4 & mask)) { - fail("4 not found"); - } - - if (w.get(3) == (5 & mask) - || w.get(5) == (5 & mask)) { - shuffleOccurred = true; - } else if (w.get(4) != (5 & mask)) { - fail("5 not found"); - } - - if (w.get(3) == (6 & mask) - || w.get(4) == (6 & mask)) { - shuffleOccurred = true; - } else if (w.get(5) != (6 & mask)) { - fail("6 not found"); - } - } - assertTrue(shuffleOccurred); - } - - @Test - public void testUpdateTopologyWithRackChange() throws Exception { - String defaultRackForThisTest = NetworkTopology.DEFAULT_REGION_AND_RACK; - repp.uninitalize(); - updateMyRack(defaultRackForThisTest); - - // Update cluster - BookieSocketAddress newAddr1 = new BookieSocketAddress("127.0.0.100", 3181); - BookieSocketAddress newAddr2 = new BookieSocketAddress("127.0.0.101", 3181); - BookieSocketAddress newAddr3 = new BookieSocketAddress("127.0.0.102", 3181); - BookieSocketAddress newAddr4 = new BookieSocketAddress("127.0.0.103", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(newAddr1.getHostName(), defaultRackForThisTest); - StaticDNSResolver.addNodeToRack(newAddr2.getHostName(), defaultRackForThisTest); - StaticDNSResolver.addNodeToRack(newAddr3.getHostName(), defaultRackForThisTest); - StaticDNSResolver.addNodeToRack(newAddr4.getHostName(), defaultRackForThisTest); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(""); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional. empty(), timer, - DISABLE_ALL, statsLogger, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(defaultRackForThisTest); - - Gauge numBookiesInDefaultRackGauge = statsLogger - .getGauge(BookKeeperClientStats.NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK); - - Set writeableBookies = new HashSet<>(); - Set readOnlyBookies = new HashSet<>(); - writeableBookies.add(newAddr1.toBookieId()); - writeableBookies.add(newAddr2.toBookieId()); - writeableBookies.add(newAddr3.toBookieId()); - writeableBookies.add(newAddr4.toBookieId()); - repp.onClusterChanged(writeableBookies, readOnlyBookies); - // only writable bookie - newAddr1 in default rack - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 4, numBookiesInDefaultRackGauge.getSample()); - - // newAddr4 rack is changed and it is not in default anymore - StaticDNSResolver - .changeRack(Collections.singletonList(newAddr3), Collections.singletonList("/default-region/r4")); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 3, numBookiesInDefaultRackGauge.getSample()); - - StaticDNSResolver - .changeRack(Collections.singletonList(newAddr1), Collections.singletonList(defaultRackForThisTest)); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 3, numBookiesInDefaultRackGauge.getSample()); - } - - @Test - public void testNumBookiesInDefaultRackGauge() throws Exception { - String defaultRackForThisTest = NetworkTopology.DEFAULT_REGION_AND_RACK; - repp.uninitalize(); - updateMyRack(defaultRackForThisTest); - - // Update cluster - BookieSocketAddress newAddr1 = new BookieSocketAddress("127.0.0.100", 3181); - BookieSocketAddress newAddr2 = new BookieSocketAddress("127.0.0.101", 3181); - BookieSocketAddress newAddr3 = new BookieSocketAddress("127.0.0.102", 3181); - BookieSocketAddress newAddr4 = new BookieSocketAddress("127.0.0.103", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(newAddr1.getHostName(), defaultRackForThisTest); - StaticDNSResolver.addNodeToRack(newAddr2.getHostName(), "/default-region/r2"); - StaticDNSResolver.addNodeToRack(newAddr3.getHostName(), "/default-region/r3"); - StaticDNSResolver.addNodeToRack(newAddr4.getHostName(), defaultRackForThisTest); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(""); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional. empty(), timer, - DISABLE_ALL, statsLogger, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(defaultRackForThisTest); - - Gauge numBookiesInDefaultRackGauge = statsLogger - .getGauge(BookKeeperClientStats.NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK); - - Set writeableBookies = new HashSet(); - writeableBookies.add(newAddr1.toBookieId()); - writeableBookies.add(newAddr2.toBookieId()); - Set readOnlyBookies = new HashSet(); - readOnlyBookies.add(newAddr3.toBookieId()); - readOnlyBookies.add(newAddr4.toBookieId()); - repp.onClusterChanged(writeableBookies, readOnlyBookies); - // only writable bookie - newAddr1 in default rack - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 1, numBookiesInDefaultRackGauge.getSample()); - - readOnlyBookies.remove(newAddr4.toBookieId()); - writeableBookies.add(newAddr4.toBookieId()); - repp.onClusterChanged(writeableBookies, readOnlyBookies); - // newAddr4 is also added to writable bookie so 2 writable bookies - - // newAddr1 and newAddr4 - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 2, numBookiesInDefaultRackGauge.getSample()); - - // newAddr4 rack is changed and it is not in default anymore - StaticDNSResolver - .changeRack(Collections.singletonList(newAddr4), Collections.singletonList("/default-region/r4")); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 1, numBookiesInDefaultRackGauge.getSample()); - - writeableBookies.clear(); - // writeableBookies is empty so 0 writable bookies in default rack - repp.onClusterChanged(writeableBookies, readOnlyBookies); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 0, numBookiesInDefaultRackGauge.getSample()); - - StaticDNSResolver - .changeRack(Collections.singletonList(newAddr1), Collections.singletonList("/default-region/r2")); - readOnlyBookies.clear(); - writeableBookies.add(newAddr1.toBookieId()); - writeableBookies.add(newAddr2.toBookieId()); - writeableBookies.add(newAddr3.toBookieId()); - writeableBookies.add(newAddr4.toBookieId()); - repp.onClusterChanged(writeableBookies, readOnlyBookies); - // newAddr1 rack is changed and it is not in default anymore. So no - // bookies in default rack anymore - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", 0, numBookiesInDefaultRackGauge.getSample()); - } - - @Test - public void testNewEnsembleExcludesDefaultRackBookiesEnforceMinNumRacks() throws Exception { - String defaultRackForThisTest = NetworkTopology.DEFAULT_REGION_AND_RACK; - repp.uninitalize(); - updateMyRack(defaultRackForThisTest); - int minNumRacksPerWriteQuorum = 4; - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorum); - // set enforceMinNumRacksPerWriteQuorum - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(""); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional. empty(), timer, - DISABLE_ALL, statsLogger, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(defaultRackForThisTest); - Gauge numBookiesInDefaultRackGauge = statsLogger - .getGauge(BookKeeperClientStats.NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK); - - int writeQuorumSize = 3; - int ackQuorumSize = 3; - int effectiveMinNumRacksPerWriteQuorum = Math.min(minNumRacksPerWriteQuorum, writeQuorumSize); - - int numOfRacks = 2 * effectiveMinNumRacksPerWriteQuorum - 1; - int numOfBookiesPerRack = 20; - BookieId[] bookieSocketAddresses = new BookieId[numOfRacks * numOfBookiesPerRack]; - - for (int i = 0; i < numOfRacks; i++) { - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieSocketAddresses[index] = new BookieSocketAddress("128.0.0." + index, 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("128.0.0." + index, "/default-region/r" + i); - } - } - - int numOfBookiesInDefaultRack = 10; - BookieId[] bookieSocketAddressesInDefaultRack = new BookieId[numOfBookiesInDefaultRack]; - for (int i = 0; i < numOfBookiesInDefaultRack; i++) { - bookieSocketAddressesInDefaultRack[i] = new BookieSocketAddress("127.0.0." + (i + 100), 3181).toBookieId(); - StaticDNSResolver.addNodeToRack("127.0.0." + (i + 100), defaultRackForThisTest); - } - - Set writableBookies = new HashSet( - Arrays.asList(bookieSocketAddresses)); - writableBookies.addAll(Arrays.asList(bookieSocketAddressesInDefaultRack)); - repp.onClusterChanged(writableBookies, new HashSet()); - assertEquals("NUM_WRITABLE_BOOKIES_IN_DEFAULT_RACK guage value", numOfBookiesInDefaultRack, - numBookiesInDefaultRackGauge.getSample()); - - /* - * in this scenario we have enough number of racks (2 * - * effectiveMinNumRacksPerWriteQuorum - 1) and more number of bookies in - * each rack. So we should be able to create ensemble for all - * ensembleSizes (as long as there are enough number of bookies in each - * rack). - * - * Since minNumRacksPerWriteQuorum is enforced, it shouldn't select node - * from default rack. - */ - EnsemblePlacementPolicy.PlacementResult> ensembleResponse; - List ensemble; - PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy; - for (int ensembleSize = effectiveMinNumRacksPerWriteQuorum; ensembleSize < 40; ensembleSize++) { - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, ackQuorumSize, null, new HashSet<>()); - ensemble = ensembleResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals("Number of writeQuorum sets covered", ensembleSize, - getNumCoveredWriteQuorums(ensemble, writeQuorumSize, clientConf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - - ensembleResponse = repp.newEnsemble(ensembleSize, writeQuorumSize, ackQuorumSize, null, new HashSet<>()); - ensemble = ensembleResponse.getResult(); - isEnsembleAdheringToPlacementPolicy = ensembleResponse.getAdheringToPolicy(); - assertEquals("Number of writeQuorum sets covered", ensembleSize, - getNumCoveredWriteQuorums(ensemble, writeQuorumSize, clientConf.getMinNumRacksPerWriteQuorum(), - repp.bookieAddressResolver)); - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, isEnsembleAdheringToPlacementPolicy); - Collection bookiesOfDefaultRackInEnsemble = CollectionUtils - .intersection(Arrays.asList(bookieSocketAddressesInDefaultRack), ensemble); - assertTrue("Ensemble is not supposed to contain bookies from default rack, but ensemble contains - " - + bookiesOfDefaultRackInEnsemble, bookiesOfDefaultRackInEnsemble.isEmpty()); - } - } - - private void testAreAckedBookiesAdheringToPlacementPolicyHelper(int minNumRacksPerWriteQuorumConfValue, - int ensembleSize, - int writeQuorumSize, - int ackQuorumSize, - int numOfBookiesInDefaultRack, - int numOfRacks, - int numOfBookiesPerRack) throws Exception { - String defaultRackForThisTest = NetworkTopology.DEFAULT_REGION_AND_RACK; - repp.uninitalize(); - updateMyRack(defaultRackForThisTest); - - ClientConfiguration conf = new ClientConfiguration(this.conf); - conf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(""); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, statsLogger, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(defaultRackForThisTest); - - List bookieSocketAddressesDefaultRack = new ArrayList<>(); - List bookieSocketAddressesNonDefaultRack = new ArrayList<>(); - Set writableBookies; - Set bookiesForEntry = new HashSet<>(); - - for (int i = 0; i < numOfRacks; i++) { - for (int j = 0; j < numOfBookiesPerRack; j++) { - int index = i * numOfBookiesPerRack + j; - bookieSocketAddressesNonDefaultRack.add(new BookieSocketAddress("128.0.0." + index, 3181).toBookieId()); - StaticDNSResolver.addNodeToRack("128.0.0." + index, "/default-region/r" + i); - } - } - - for (int i = 0; i < numOfBookiesInDefaultRack; i++) { - bookieSocketAddressesDefaultRack.add(new BookieSocketAddress("127.0.0." + (i + 100), 3181).toBookieId()); - StaticDNSResolver.addNodeToRack("127.0.0." + (i + 100), defaultRackForThisTest); - } - - writableBookies = new HashSet<>(bookieSocketAddressesNonDefaultRack); - writableBookies.addAll(bookieSocketAddressesDefaultRack); - repp.onClusterChanged(writableBookies, new HashSet<>()); - - // Case 1 : Bookies in the ensemble from the same rack. - // Manually crafting the ensemble here to create the error case when the check should return false - - List ensemble = new ArrayList<>(bookieSocketAddressesDefaultRack); - for (int entryId = 0; entryId < 10; entryId++) { - DistributionSchedule ds = new RoundRobinDistributionSchedule(writeQuorumSize, ackQuorumSize, ensembleSize); - DistributionSchedule.WriteSet ws = ds.getWriteSet(entryId); - - for (int i = 0; i < ws.size(); i++) { - bookiesForEntry.add(ensemble.get(ws.get(i))); - } - - assertFalse(repp.areAckedBookiesAdheringToPlacementPolicy(bookiesForEntry, writeQuorumSize, ackQuorumSize)); - } - - // Case 2 : Bookies in the ensemble from the different racks - - EnsemblePlacementPolicy.PlacementResult> - ensembleResponse = repp.newEnsemble(ensembleSize, - writeQuorumSize, - ackQuorumSize, - null, - new HashSet<>()); - ensemble = ensembleResponse.getResult(); - for (int entryId = 0; entryId < 10; entryId++) { - DistributionSchedule ds = new RoundRobinDistributionSchedule(writeQuorumSize, ackQuorumSize, ensembleSize); - DistributionSchedule.WriteSet ws = ds.getWriteSet(entryId); - - for (int i = 0; i < ws.size(); i++) { - bookiesForEntry.add(ensemble.get(ws.get(i))); - } - - assertTrue(repp.areAckedBookiesAdheringToPlacementPolicy(bookiesForEntry, writeQuorumSize, ackQuorumSize)); - } - } - - /** - * This tests areAckedBookiesAdheringToPlacementPolicy function in RackawareEnsemblePlacementPolicy. - */ - @Test - public void testAreAckedBookiesAdheringToPlacementPolicy() throws Exception { - testAreAckedBookiesAdheringToPlacementPolicyHelper(2, 7, 3, 2, 7, 3, 3); - testAreAckedBookiesAdheringToPlacementPolicyHelper(4, 6, 3, 2, 6, 3, 3); - testAreAckedBookiesAdheringToPlacementPolicyHelper(5, 7, 5, 3, 7, 5, 2); - } - - @SuppressWarnings("unchecked") - @Test - public void testReplaceToAdherePlacementPolicy() throws Exception { - final BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - final BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - final BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - final BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - final BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - final BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - final BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.7", 3181); - final BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.8", 3181); - final BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.9", 3181); - - final String rackName1 = NetworkTopology.DEFAULT_REGION + "/r1"; - final String rackName2 = NetworkTopology.DEFAULT_REGION + "/r2"; - final String rackName3 = NetworkTopology.DEFAULT_REGION + "/r3"; - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr5.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr6.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr7.getSocketAddress().getAddress().getHostAddress(), rackName3); - StaticDNSResolver.addNodeToRack(addr8.getSocketAddress().getAddress().getHostAddress(), rackName3); - StaticDNSResolver.addNodeToRack(addr9.getSocketAddress().getAddress().getHostAddress(), rackName3); - - // Update cluster - final Set addrs = new HashSet<>(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - - final ClientConfiguration newConf = new ClientConfiguration(conf); - newConf.setDiskWeightBasedPlacementEnabled(false); - newConf.setMinNumRacksPerWriteQuorum(2); - newConf.setEnforceMinNumRacksPerWriteQuorum(true); - - repp.initialize(newConf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet<>()); - final Map bookieInfoMap = new HashMap<>(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr5.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr6.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr7.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr8.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr9.toBookieId(), new BookieInfo(100L, 100L)); - - repp.updateBookieInfo(bookieInfoMap); - - final Set excludeList = new HashSet<>(); - final int ensembleSize = 7; - final int writeQuorumSize = 2; - final int ackQuorumSize = 2; - - final BookieRackMatcher rack1 = new BookieRackMatcher(rackName1); - final BookieRackMatcher rack2 = new BookieRackMatcher(rackName2); - final BookieRackMatcher rack3 = new BookieRackMatcher(rackName3); - final BookieRackMatcher rack12 = new BookieRackMatcher(rackName1, rackName2); - final BookieRackMatcher rack13 = new BookieRackMatcher(rackName1, rackName3); - final BookieRackMatcher rack23 = new BookieRackMatcher(rackName2, rackName3); - final BookieRackMatcher rack123 = new BookieRackMatcher(rackName1, rackName2, rackName3); - final Consumer, Matcher>>> test = (pair) -> { - // RackawareEnsemblePlacementPolicyImpl#isEnsembleAdheringToPlacementPolicy - // is not scope of this test case. So, use the method in assertion for convenience. - assertEquals(PlacementPolicyAdherence.FAIL, - repp.isEnsembleAdheringToPlacementPolicy(pair.getLeft(), writeQuorumSize, ackQuorumSize)); - final EnsemblePlacementPolicy.PlacementResult> result = - repp.replaceToAdherePlacementPolicy(ensembleSize, writeQuorumSize, ackQuorumSize, - excludeList, pair.getLeft()); - if (LOG.isDebugEnabled()) { - LOG.debug("input: {}, result: {}", pair.getLeft(), result.getResult()); - } - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, result.getAdheringToPolicy()); - assertThat(result.getResult(), pair.getRight()); - }; - - for (int i = 0; i < 1000; i++) { - test.accept(Pair.of(Arrays.asList(addr1.toBookieId(), addr4.toBookieId(), addr7.toBookieId(), - addr2.toBookieId(), addr5.toBookieId(), addr8.toBookieId(), addr9.toBookieId()), - // first, same, same, same, same, same, condition[0] - contains(is(addr1.toBookieId()), is(addr4.toBookieId()), is(addr7.toBookieId()), - is(addr2.toBookieId()), is(addr5.toBookieId()), is(addr8.toBookieId()), - is(addr6.toBookieId())))); - - test.accept(Pair.of(Arrays.asList(addr6.toBookieId(), addr4.toBookieId(), addr7.toBookieId(), - addr2.toBookieId(), addr5.toBookieId(), addr8.toBookieId(), addr3.toBookieId()), - // first, condition[0], same, same, same, same, same - contains(is(addr6.toBookieId()), is(addr1.toBookieId()), is(addr7.toBookieId()), - is(addr2.toBookieId()), is(addr5.toBookieId()), is(addr8.toBookieId()), - is(addr3.toBookieId())))); - - test.accept(Pair.of(Arrays.asList(addr1.toBookieId(), addr2.toBookieId(), addr3.toBookieId(), - addr4.toBookieId(), addr5.toBookieId(), addr6.toBookieId(), addr7.toBookieId()), - // first, candidate[0], same, same, candidate[0], same, same - contains(is(addr1.toBookieId()), is(rack3), is(addr3.toBookieId()), - is(addr4.toBookieId()), is(rack13), is(addr6.toBookieId()), is(addr7.toBookieId())))); - - test.accept(Pair.of(Arrays.asList(addr1.toBookieId(), addr2.toBookieId(), addr4.toBookieId(), - addr5.toBookieId(), addr7.toBookieId(), addr8.toBookieId(), addr9.toBookieId()), - contains(is(addr1.toBookieId()), is(rack23), is(rack123), is(rack123), - is(rack123), is(rack123), is(rack23)))); - } - StaticDNSResolver.reset(); - } - - @SuppressWarnings("unchecked") - @Test - public void testReplaceToAdherePlacementPolicyWithOutOfOrder() throws Exception { - final BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - final BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - final BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - final BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - final BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - final BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - - final String rackName1 = NetworkTopology.DEFAULT_REGION + "/r1"; - final String rackName2 = NetworkTopology.DEFAULT_REGION + "/r2"; - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr5.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr6.getSocketAddress().getAddress().getHostAddress(), rackName2); - - // Update cluster - final Set addrs = new HashSet<>(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - - final ClientConfiguration newConf = new ClientConfiguration(conf); - newConf.setDiskWeightBasedPlacementEnabled(false); - newConf.setMinNumRacksPerWriteQuorum(2); - newConf.setEnforceMinNumRacksPerWriteQuorum(true); - - repp.initialize(newConf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet<>()); - final Map bookieInfoMap = new HashMap<>(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr5.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr6.toBookieId(), new BookieInfo(100L, 100L)); - - repp.updateBookieInfo(bookieInfoMap); - - final Set excludeList = new HashSet<>(); - final int ensembleSize = 6; - final int writeQuorumSize = 2; - final int ackQuorumSize = 2; - - final Consumer, Matcher>>> test = (pair) -> { - // RackawareEnsemblePlacementPolicyImpl#isEnsembleAdheringToPlacementPolicy - // is not scope of this test case. So, use the method in assertion for convenience. - assertEquals(PlacementPolicyAdherence.FAIL, - repp.isEnsembleAdheringToPlacementPolicy(pair.getLeft(), writeQuorumSize, ackQuorumSize)); - final EnsemblePlacementPolicy.PlacementResult> result = - repp.replaceToAdherePlacementPolicy(ensembleSize, writeQuorumSize, ackQuorumSize, - excludeList, pair.getLeft()); - if (LOG.isDebugEnabled()) { - LOG.debug("input: {}, result: {}", pair.getLeft(), result.getResult()); - } - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, result.getAdheringToPolicy()); - }; - - for (int i = 0; i < 1000; i++) { - //All bookies already in the ensemble, the bookie order not adhere the placement policy. - test.accept(Pair.of(Arrays.asList(addr1.toBookieId(), addr2.toBookieId(), addr3.toBookieId(), - addr4.toBookieId(), addr5.toBookieId(), addr6.toBookieId()), - //The result is not predict. We know the best min replace place is 2. - //1,2,3,4,5,6 => 1,5,3,4,2,6 - //But maybe the final result is 1,6,3,4,2,5. - //When we from index 0 to replace, the first bookie(1) is /rack1, we only pick /rack2 bookie - //for the second bookie, so we can choose 4,5,6, the choice is random. If we pick 6 for the second, - // the final result is 1,6,3,4,2,5. If we pick 5 for the second, the final result is 1,5,3,4,2,6 - null)); - } - StaticDNSResolver.reset(); - } - - @SuppressWarnings("unchecked") - @Test - public void testReplaceToAdherePlacementPolicyWithNoMoreRackBookie() throws Exception { - final BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - final BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - final BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - final BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - final BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - final BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - - final String rackName1 = NetworkTopology.DEFAULT_REGION + "/r1"; - final String rackName2 = NetworkTopology.DEFAULT_REGION + "/r2"; - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr5.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr6.getSocketAddress().getAddress().getHostAddress(), rackName2); - - // Update cluster - final Set addrs = new HashSet<>(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - - final ClientConfiguration newConf = new ClientConfiguration(conf); - newConf.setDiskWeightBasedPlacementEnabled(false); - newConf.setMinNumRacksPerWriteQuorum(2); - newConf.setEnforceMinNumRacksPerWriteQuorum(true); - - repp.initialize(newConf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet<>()); - final Map bookieInfoMap = new HashMap<>(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr5.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr6.toBookieId(), new BookieInfo(100L, 100L)); - - repp.updateBookieInfo(bookieInfoMap); - - final Set excludeList = new HashSet<>(); - final int ensembleSize = 3; - final int writeQuorumSize = 2; - final int ackQuorumSize = 2; - - final Consumer, Matcher>>> test = (pair) -> { - // RackawareEnsemblePlacementPolicyImpl#isEnsembleAdheringToPlacementPolicy - // is not scope of this test case. So, use the method in assertion for convenience. - assertEquals(PlacementPolicyAdherence.FAIL, - repp.isEnsembleAdheringToPlacementPolicy(pair.getLeft(), writeQuorumSize, ackQuorumSize)); - final EnsemblePlacementPolicy.PlacementResult> result = - repp.replaceToAdherePlacementPolicy(ensembleSize, writeQuorumSize, ackQuorumSize, - excludeList, pair.getLeft()); - if (LOG.isDebugEnabled()) { - LOG.debug("input: {}, result: {}", pair.getLeft(), result.getResult()); - } - assertEquals(PlacementPolicyAdherence.FAIL, result.getAdheringToPolicy()); - assertEquals(0, result.getResult().size()); - }; - - for (int i = 0; i < 1000; i++) { - test.accept(Pair.of(Arrays.asList(addr1.toBookieId(), addr2.toBookieId(), addr4.toBookieId()), - null)); - } - StaticDNSResolver.reset(); - } - - @SuppressWarnings("unchecked") - @Test - public void testReplaceToAdherePlacementPolicyWithUnknowBookie() throws Exception { - final BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - final BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - final BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - final BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - final BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - final BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - - final String rackName1 = NetworkTopology.DEFAULT_REGION + "/r1"; - final String rackName2 = NetworkTopology.DEFAULT_REGION + "/r2"; - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr2.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr3.getSocketAddress().getAddress().getHostAddress(), rackName1); - StaticDNSResolver.addNodeToRack(addr4.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr5.getSocketAddress().getAddress().getHostAddress(), rackName2); - StaticDNSResolver.addNodeToRack(addr6.getSocketAddress().getAddress().getHostAddress(), rackName2); - - // Update cluster - final Set addrs = new HashSet<>(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - - final ClientConfiguration newConf = new ClientConfiguration(conf); - newConf.setDiskWeightBasedPlacementEnabled(false); - newConf.setMinNumRacksPerWriteQuorum(2); - newConf.setEnforceMinNumRacksPerWriteQuorum(true); - - repp.initialize(newConf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp.onClusterChanged(addrs, new HashSet<>()); - final Map bookieInfoMap = new HashMap<>(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr5.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr6.toBookieId(), new BookieInfo(100L, 100L)); - - repp.updateBookieInfo(bookieInfoMap); - - final Set excludeList = new HashSet<>(); - final int ensembleSize = 6; - final int writeQuorumSize = 2; - final int ackQuorumSize = 2; - - final BookieRackMatcher rack1 = new BookieRackMatcher(rackName1); - - final Consumer, Matcher>>> test = (pair) -> { - // RackawareEnsemblePlacementPolicyImpl#isEnsembleAdheringToPlacementPolicy - // is not scope of this test case. So, use the method in assertion for convenience. - assertEquals(PlacementPolicyAdherence.FAIL, - repp.isEnsembleAdheringToPlacementPolicy(pair.getLeft(), writeQuorumSize, ackQuorumSize)); - final EnsemblePlacementPolicy.PlacementResult> result = - repp.replaceToAdherePlacementPolicy(ensembleSize, writeQuorumSize, ackQuorumSize, - excludeList, pair.getLeft()); - if (LOG.isDebugEnabled()) { - LOG.debug("input: {}, result: {}", pair.getLeft(), result.getResult()); - } - assertEquals(PlacementPolicyAdherence.MEETS_STRICT, result.getAdheringToPolicy()); - assertThat(result.getResult(), pair.getRight()); - }; - - for (int i = 0; i < 1000; i++) { - test.accept(Pair.of(Arrays.asList(BookieId.parse("127.0.0.10:3181"), BookieId.parse("127.0.0.11:3181"), - addr3.toBookieId(), - addr4.toBookieId(), addr5.toBookieId(), addr6.toBookieId()), - contains(is(rack1), is(addr5.toBookieId()), is(addr3.toBookieId()), - is(addr4.toBookieId()), is(rack1), is(addr6.toBookieId())))); - } - StaticDNSResolver.reset(); - } - - private static class BookieRackMatcher extends TypeSafeMatcher { - final List expectedRacks; - - public BookieRackMatcher(String... expectedRacks) { - this.expectedRacks = Arrays.asList(expectedRacks); - } - - @Override - protected boolean matchesSafely(BookieId bookieId) { - return expectedRacks.contains(StaticDNSResolver.getRack(bookieId.toString().split(":")[0])); - } - - @Override - public void describeTo(Description description) { - description.appendText("expected racks " + expectedRacks); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicyUsingScript.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicyUsingScript.java deleted file mode 100644 index c61cdb6138b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicyUsingScript.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicy.REPP_DNS_RESOLVER_CLASS; -import static org.apache.bookkeeper.feature.SettableFeatureProvider.DISABLE_ALL; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.netty.util.HashedWheelTimer; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.net.CommonConfigurationKeys; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.bookkeeper.net.ScriptBasedMapping; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.Shell; -import org.junit.After; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * In this testsuite, ScriptBasedMapping is used as DNS_RESOLVER_CLASS for - * mapping nodes to racks. Shell Script - - * src/test/resources/networkmappingscript.sh is used in ScriptBasedMapping for - * resolving racks. This script maps HostAddress to rack depending on the last - * character of the HostAddress string. for eg. 127.0.0.1 :- /1, 127.0.0.2 :- - * /2, 99.12.34.21 :- /1 - * - *

This testsuite has same testscenarios as in - * TestRackawareEnsemblePlacementPolicy.java. - * - *

For now this Testsuite works only on Unix based OS. - */ -public class TestRackawareEnsemblePlacementPolicyUsingScript { - - static final Logger LOG = LoggerFactory.getLogger(TestRackawareEnsemblePlacementPolicyUsingScript.class); - - HashedWheelTimer timer; - RackawareEnsemblePlacementPolicy repp; - ClientConfiguration conf = new ClientConfiguration(); - - @Before - public void setUp() throws Exception { - conf.setProperty(REPP_DNS_RESOLVER_CLASS, ScriptBasedMapping.class.getName()); - conf.setProperty(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY, - "src/test/resources/networkmappingscript.sh"); - timer = new HashedWheelTimer( - new ThreadFactoryBuilder().setNameFormat("TestTimer-%d").build(), - conf.getTimeoutTimerTickDurationMs(), TimeUnit.MILLISECONDS, - conf.getTimeoutTimerNumTicks()); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - } - - @After - public void tearDown() throws Exception { - repp.uninitalize(); - } - - private void ignoreTestIfItIsWindowsOS() { - Assume.assumeTrue(!Shell.WINDOWS); - } - - @Test - public void testReplaceBookieWithEnoughBookiesInSameRack() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.1.2", 3181); // /2 rack - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); // /4 rack - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - BookieId replacedBookie = repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), - addr2.toBookieId(), new HashSet<>()).getResult(); - assertEquals(addr3.toBookieId(), replacedBookie); - } - - @Test - public void testReplaceBookieWithEnoughBookiesInDifferentRack() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); // /3 rack - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); // /4 rack - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - BookieId replacedBookie = repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), - addr2.toBookieId(), excludedAddrs).getResult(); - - assertFalse(addr1.toBookieId().equals(replacedBookie)); - assertTrue(addr3.toBookieId().equals(replacedBookie) - || addr4.toBookieId().equals(replacedBookie)); - } - - @Test - public void testReplaceBookieWithNotEnoughBookies() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); // /3 rack - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); // /4 rack - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - excludedAddrs.add(addr3.toBookieId()); - excludedAddrs.add(addr4.toBookieId()); - try { - repp.replaceBookie(1, 1, 1, null, new ArrayList(), addr2.toBookieId(), excludedAddrs); - fail("Should throw BKNotEnoughBookiesException when there is not enough bookies"); - } catch (BKNotEnoughBookiesException bnebe) { - // should throw not BKNotEnoughBookiesException - } - } - - /* - * Test that even in case of script mapping error - * we are getting default rack that makes sense for the policy. - * i.e. if all nodes in rack-aware policy use /rack format - * but one gets node /default-region/default-rack the node addition to topology will fail. - * - * This case adds node with non-default rack, then adds nodes with one on default rack. - */ - @Test - public void testReplaceBookieWithScriptMappingError() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr0 = new BookieSocketAddress("127.0.0.0", 3181); // error mapping to rack here - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - - // Update cluster, add node that maps to non-default rack - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - - repp.onClusterChanged(addrs, new HashSet()); - - addrs = new HashSet(); - addrs.add(addr0.toBookieId()); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - BookieId replacedBookie = repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), - addr2.toBookieId(), excludedAddrs).getResult(); - - assertFalse(addr1.toBookieId().equals(replacedBookie)); - assertFalse(addr2.toBookieId().equals(replacedBookie)); - assertTrue(addr0.toBookieId().equals(replacedBookie)); - } - - /* - * Test that even in case of script mapping error - * we are getting default rack that makes sense for the policy. - * i.e. if all nodes in rack-aware policy use /rack format - * but one gets node /default-region/default-rack the node addition to topology will fail. - * - * This case adds node with default rack, then adds nodes with non-default rack. - * Almost the same as testReplaceBookieWithScriptMappingError but different order of addition. - */ - @Test - public void testReplaceBookieWithScriptMappingError2() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr0 = new BookieSocketAddress("127.0.0.0", 3181); // error mapping to rack here - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - - // Update cluster, add node that maps to default rack first - Set addrs = new HashSet(); - addrs.add(addr0.toBookieId()); - - repp.onClusterChanged(addrs, new HashSet()); - - addrs = new HashSet(); - addrs.add(addr0.toBookieId()); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - BookieId replacedBookie = repp.replaceBookie(1, 1, 1, null, new ArrayList<>(), - addr2.toBookieId(), excludedAddrs).getResult(); - - assertFalse(addr1.toBookieId().equals(replacedBookie)); - assertFalse(addr2.toBookieId().equals(replacedBookie)); - assertTrue(addr0.toBookieId().equals(replacedBookie)); - } - - @Test - public void testNewEnsembleWithSingleRack() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.1.1", 3181); // /1 rack - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.2.1", 3181); // /1 rack - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.3.1", 3181); // /1 rack - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List ensemble = repp.newEnsemble(3, 2, 2, null, - new HashSet<>()).getResult(); - assertEquals(0, getNumCoveredWriteQuorums(ensemble, 2)); - List ensemble2 = repp.newEnsemble(4, 2, 2, null, - new HashSet<>()).getResult(); - assertEquals(0, getNumCoveredWriteQuorums(ensemble2, 2)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testNewEnsembleWithMultipleRacks() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.1.2", 3181); // /2 rack - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.2.2", 3181); // /2 rack - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List ensemble = repp.newEnsemble(3, 2, 2, null, - new HashSet<>()).getResult(); - int numCovered = getNumCoveredWriteQuorums(ensemble, 2); - assertTrue(numCovered == 2); - List ensemble2 = repp.newEnsemble(4, 2, 2, null, - new HashSet<>()).getResult(); - numCovered = getNumCoveredWriteQuorums(ensemble2, 2); - assertTrue(numCovered == 2); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception"); - } - } - - @Test - public void testNewEnsembleWithEnoughRacks() throws Exception { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); // /3 rack - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); // /4 rack - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.1.1", 3181); // /1 rack - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.1.2", 3181); // /2 rack - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.1.3", 3181); // /3 rack - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.1.4", 3181); // /4 rack - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List ensemble1 = repp.newEnsemble(3, 2, 2, null, - new HashSet<>()).getResult(); - assertEquals(3, getNumCoveredWriteQuorums(ensemble1, 2)); - List ensemble2 = repp.newEnsemble(4, 2, 2, null, - new HashSet<>()).getResult(); - assertEquals(4, getNumCoveredWriteQuorums(ensemble2, 2)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception."); - } - } - - /** - * Test for BOOKKEEPER-633. - */ - - @Test - public void testRemoveBookieFromCluster() { - ignoreTestIfItIsWindowsOS(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); // /1 rack - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); // /2 rack - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.1.2", 3181); // /2 rack - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); // /4 rack - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - } - - @Test - public void testNetworkTopologyScriptFileNameIsEmpty() throws Exception { - ignoreTestIfItIsWindowsOS(); - repp.uninitalize(); - - ClientConfiguration newConf = new ClientConfiguration(); - newConf.setProperty(REPP_DNS_RESOLVER_CLASS, ScriptBasedMapping.class.getName()); - newConf.setProperty(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY, ""); - newConf.setEnforceMinNumRacksPerWriteQuorum(false); - timer = new HashedWheelTimer(new ThreadFactoryBuilder().setNameFormat("TestTimer-%d").build(), - newConf.getTimeoutTimerTickDurationMs(), TimeUnit.MILLISECONDS, newConf.getTimeoutTimerNumTicks()); - - repp = new RackawareEnsemblePlacementPolicy(); - try { - repp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - } catch (RuntimeException re) { - fail("EnforceMinNumRacksPerWriteQuorum is not set, so repp.initialize should succeed even if" - + " networkTopologyScriptFileName is empty"); - } - repp.uninitalize(); - - newConf.setEnforceMinNumRacksPerWriteQuorum(true); - repp = new RackawareEnsemblePlacementPolicy(); - try { - repp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - fail("EnforceMinNumRacksPerWriteQuorum is set, so repp.initialize should fail if" - + " networkTopologyScriptFileName is empty"); - } catch (RuntimeException re) { - } - repp.uninitalize(); - - newConf.setProperty(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY, - "src/test/resources/networkmappingscript.sh"); - try { - repp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - } catch (RuntimeException re) { - fail("EnforceMinNumRacksPerWriteQuorum is set and networkTopologyScriptFileName is not empty," - + " so it should succeed"); - } - repp.uninitalize(); - } - - @Test - public void testIfValidateConfFails() throws Exception { - ignoreTestIfItIsWindowsOS(); - repp.uninitalize(); - - ClientConfiguration newConf = new ClientConfiguration(); - newConf.setProperty(REPP_DNS_RESOLVER_CLASS, ScriptBasedMapping.class.getName()); - /* - * this script, exits with error value if no argument is passed to it. - * So mapping.validateConf will fail. - */ - newConf.setProperty(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY, - "src/test/resources/networkmappingscriptwithargs.sh"); - timer = new HashedWheelTimer(new ThreadFactoryBuilder().setNameFormat("TestTimer-%d").build(), - newConf.getTimeoutTimerTickDurationMs(), TimeUnit.MILLISECONDS, newConf.getTimeoutTimerNumTicks()); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(newConf, Optional. empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - repp.uninitalize(); - repp = new RackawareEnsemblePlacementPolicy(); - try { - repp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - } catch (RuntimeException re) { - fail("EnforceMinNumRacksPerWriteQuorum is not set, so repp.initialize should succeed" - + " even if mapping.validateConf fails"); - } - - newConf.setEnforceMinNumRacksPerWriteQuorum(true); - repp.uninitalize(); - repp = new RackawareEnsemblePlacementPolicy(); - try { - repp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - fail("EnforceMinNumRacksPerWriteQuorum is set, so repp.initialize should fail" - + " if mapping.validateConf fails"); - } catch (RuntimeException re) { - - } - - /* - * this script returns successfully even if no argument is passed to it. - * So mapping.validateConf will succeed. - */ - newConf.setProperty(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY, - "src/test/resources/networkmappingscript.sh"); - repp.uninitalize(); - repp = new RackawareEnsemblePlacementPolicy(); - try { - repp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - } catch (RuntimeException re) { - fail("EnforceMinNumRacksPerWriteQuorum is set, and mapping.validateConf succeeds." - + " So repp.initialize should succeed"); - } - } - - private int getNumCoveredWriteQuorums(List ensemble, int writeQuorumSize) - throws Exception { - int ensembleSize = ensemble.size(); - int numCoveredWriteQuorums = 0; - for (int i = 0; i < ensembleSize; i++) { - Set racks = new HashSet(); - for (int j = 0; j < writeQuorumSize; j++) { - int bookieIdx = (i + j) % ensembleSize; - BookieId addr = ensemble.get(bookieIdx); - String hostAddress = repp.bookieAddressResolver.resolve(addr) - .getSocketAddress().getAddress().getHostAddress(); - String rack = "/" + hostAddress.charAt(hostAddress.length() - 1); - racks.add(rack); - } - numCoveredWriteQuorums += (racks.size() > 1 ? 1 : 0); - } - return numCoveredWriteQuorums; - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawarePolicyNotificationUpdates.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawarePolicyNotificationUpdates.java deleted file mode 100644 index 03ecc5b61d0..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawarePolicyNotificationUpdates.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicyImpl.REPP_DNS_RESOLVER_CLASS; -import static org.apache.bookkeeper.feature.SettableFeatureProvider.DISABLE_ALL; - -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.netty.util.HashedWheelTimer; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.bookkeeper.net.NetworkTopology; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the rackaware ensemble placement policy. - */ -public class TestRackawarePolicyNotificationUpdates extends TestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestRackawarePolicyNotificationUpdates.class); - - RackawareEnsemblePlacementPolicy repp; - HashedWheelTimer timer; - ClientConfiguration conf = new ClientConfiguration(); - - @Override - protected void setUp() throws Exception { - super.setUp(); - conf.setProperty(REPP_DNS_RESOLVER_CLASS, StaticDNSResolver.class.getName()); - - StaticDNSResolver.reset(); - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostAddress(), - NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack("127.0.0.1", NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack("localhost", NetworkTopology.DEFAULT_REGION_AND_RACK); - LOG.info("Set up static DNS Resolver."); - - timer = new HashedWheelTimer(new ThreadFactoryBuilder().setNameFormat("TestTimer-%d").build(), - conf.getTimeoutTimerTickDurationMs(), TimeUnit.MILLISECONDS, conf.getTimeoutTimerNumTicks()); - - repp = new RackawareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional. empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - } - - @Override - protected void tearDown() throws Exception { - repp.uninitalize(); - super.tearDown(); - } - - @Test - public void testNotifyRackChange() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.1.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.1.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.1.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.1.4", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/default-region/rack-1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/default-region/rack-2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/default-region/rack-2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/rack-2"); - int numOfAvailableRacks = 2; - - // Update cluster - Set addrs = Sets.newHashSet(addr1.toBookieId(), - addr2.toBookieId(), addr3.toBookieId(), addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet<>()); - - int ensembleSize = 3; - int writeQuorumSize = 2; - int acqQuorumSize = 2; - List ensemble = repp.newEnsemble(ensembleSize, writeQuorumSize, - acqQuorumSize, Collections.emptyMap(), Collections.emptySet()).getResult(); - int numCovered = TestRackawareEnsemblePlacementPolicy.getNumCoveredWriteQuorums(ensemble, writeQuorumSize, - conf.getMinNumRacksPerWriteQuorum(), repp.bookieAddressResolver); - assertTrue(numCovered >= 1 && numCovered < 3); - assertTrue(ensemble.contains(addr1.toBookieId())); - - List bookieAddressList = new ArrayList<>(); - List rackList = new ArrayList<>(); - bookieAddressList.add(addr2); - rackList.add("/default-region/rack-3"); - StaticDNSResolver.changeRack(bookieAddressList, rackList); - numOfAvailableRacks = numOfAvailableRacks + 1; - acqQuorumSize = 1; - ensemble = repp.newEnsemble(ensembleSize, writeQuorumSize, acqQuorumSize, Collections.emptyMap(), - Collections.emptySet()).getResult(); - assertEquals(3, TestRackawareEnsemblePlacementPolicy.getNumCoveredWriteQuorums(ensemble, writeQuorumSize, - conf.getMinNumRacksPerWriteQuorum(), repp.bookieAddressResolver)); - assertTrue(ensemble.contains(addr1.toBookieId())); - assertTrue(ensemble.contains(addr2.toBookieId())); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadEntryListener.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadEntryListener.java deleted file mode 100644 index 16a2616ca4d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadEntryListener.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryListener; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit tests for {@link org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryListener}. - */ -public class TestReadEntryListener extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(TestReadEntryListener.class); - - final DigestType digestType; - final byte[] passwd = "read-entry-listener".getBytes(); - - public TestReadEntryListener() { - super(6); - this.digestType = DigestType.CRC32; - } - - long getLedgerToRead(int ensemble, int writeQuorum, int ackQuorum, int numEntries) - throws Exception { - LedgerHandle lh = bkc.createLedger(ensemble, writeQuorum, ackQuorum, digestType, passwd); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("" + i).getBytes()); - } - lh.close(); - return lh.getId(); - } - - static class EntryWithRC { - final LedgerEntry entry; - final int rc; - - EntryWithRC(int rc, LedgerEntry entry) { - this.rc = rc; - this.entry = entry; - } - } - - static class LatchListener implements ReadEntryListener { - - final CountDownLatch l; - final Map resultCodes; - boolean inOrder = true; - long nextEntryId; - - LatchListener(long startEntryId, int numEntries) { - l = new CountDownLatch(numEntries); - resultCodes = new HashMap(); - this.nextEntryId = startEntryId; - } - - @Override - public void onEntryComplete(int rc, LedgerHandle lh, LedgerEntry entry, Object ctx) { - long entryId; - if (BKException.Code.OK == rc) { - if (nextEntryId != entry.getEntryId()) { - inOrder = false; - } - entryId = entry.getEntryId(); - } else { - entryId = nextEntryId; - } - resultCodes.put(entryId, new EntryWithRC(rc, entry)); - ++nextEntryId; - l.countDown(); - } - - void expectComplete() throws Exception { - l.await(); - } - - boolean isInOrder() { - return inOrder; - } - } - - ListenerBasedPendingReadOp createReadOp(LedgerHandle lh, long from, long to, ReadEntryListener listener) { - return new ListenerBasedPendingReadOp(lh, bkc.getClientCtx(), from, to, listener, null, false); - } - - void basicReadTest(boolean parallelRead) throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 2, 2, numEntries); - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - // read single entry - for (int i = 0; i < numEntries; i++) { - LatchListener listener = new LatchListener(i, 1); - ListenerBasedPendingReadOp readOp = createReadOp(lh, i, i, listener); - readOp.parallelRead(parallelRead).submit(); - listener.expectComplete(); - assertEquals(1, listener.resultCodes.size()); - EntryWithRC entry = listener.resultCodes.get((long) i); - assertNotNull(entry); - assertEquals(BKException.Code.OK, entry.rc); - assertEquals(i, Integer.parseInt(new String(entry.entry.getEntry()))); - assertTrue(listener.isInOrder()); - } - - // read multiple entries - LatchListener listener = new LatchListener(0L, numEntries); - ListenerBasedPendingReadOp readOp = createReadOp(lh, 0, numEntries - 1, listener); - readOp.parallelRead(parallelRead).submit(); - listener.expectComplete(); - assertEquals(numEntries, listener.resultCodes.size()); - for (int i = 0; i < numEntries; i++) { - EntryWithRC entry = listener.resultCodes.get((long) i); - assertNotNull(entry); - assertEquals(BKException.Code.OK, entry.rc); - assertEquals(i, Integer.parseInt(new String(entry.entry.getEntry()))); - } - assertTrue(listener.isInOrder()); - - lh.close(); - } - - @Test - public void testBasicEnableParallelRead() throws Exception { - basicReadTest(true); - } - - @Test - public void testBasicDisableParallelRead() throws Exception { - basicReadTest(false); - } - - private void readMissingEntriesTest(boolean parallelRead) throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 2, 2, numEntries); - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - // read single entry - LatchListener listener = new LatchListener(11L, 1); - ListenerBasedPendingReadOp readOp = createReadOp(lh, 11, 11, listener); - readOp.parallelRead(parallelRead).submit(); - listener.expectComplete(); - assertEquals(1, listener.resultCodes.size()); - EntryWithRC entry = listener.resultCodes.get(11L); - assertNotNull(entry); - assertEquals(BKException.Code.NoSuchEntryException, entry.rc); - assertTrue(listener.isInOrder()); - - // read multiple missing entries - listener = new LatchListener(11L, 3); - readOp = createReadOp(lh, 11, 13, listener); - readOp.parallelRead(parallelRead).submit(); - listener.expectComplete(); - assertEquals(3, listener.resultCodes.size()); - assertTrue(listener.isInOrder()); - - for (int i = 11; i <= 13; i++) { - entry = listener.resultCodes.get((long) i); - assertNotNull(entry); - assertEquals(BKException.Code.NoSuchEntryException, entry.rc); - } - - // read multiple entries with missing entries - listener = new LatchListener(5L, 10); - readOp = createReadOp(lh, 5L, 14L, listener); - readOp.parallelRead(parallelRead).submit(); - listener.expectComplete(); - assertEquals(10, listener.resultCodes.size()); - assertTrue(listener.isInOrder()); - - for (long i = 5L; i <= 14L; i++) { - entry = listener.resultCodes.get(i); - assertNotNull(entry); - if (i < 10L) { - assertEquals(BKException.Code.OK, entry.rc); - assertEquals(i, Integer.parseInt(new String(entry.entry.getEntry()))); - } else { - assertEquals(BKException.Code.NoSuchEntryException, entry.rc); - } - } - - lh.close(); - } - - @Test - public void testReadMissingEntriesEnableParallelRead() throws Exception { - readMissingEntriesTest(true); - } - - @Test - public void testReadMissingEntriesDisableParallelRead() throws Exception { - readMissingEntriesTest(false); - } - - private void readWithFailedBookiesTest(boolean parallelRead) throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 3, 3, numEntries); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = - lh.getLedgerMetadata().getEnsembleAt(5); - // kill two bookies - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - - // read multiple entries - LatchListener listener = new LatchListener(0L, numEntries); - ListenerBasedPendingReadOp readOp = createReadOp(lh, 0, numEntries - 1, listener); - readOp.parallelRead(parallelRead).submit(); - listener.expectComplete(); - assertEquals(numEntries, listener.resultCodes.size()); - for (int i = 0; i < numEntries; i++) { - EntryWithRC entry = listener.resultCodes.get((long) i); - assertNotNull(entry); - assertEquals(BKException.Code.OK, entry.rc); - assertEquals(i, Integer.parseInt(new String(entry.entry.getEntry()))); - } - - lh.close(); - } - - @Test - public void testReadWithFailedBookiesEnableParallelRead() throws Exception { - readWithFailedBookiesTest(true); - } - - @Test - public void testReadWithFailedBookiesDisableParallelRead() throws Exception { - readWithFailedBookiesTest(false); - } - - private void readFailureWithFailedBookiesTest(boolean parallelRead) throws Exception { - int numEntries = 10; - - long id = getLedgerToRead(5, 3, 3, numEntries); - - LedgerHandle lh = bkc.openLedger(id, digestType, passwd); - - List ensemble = - lh.getLedgerMetadata().getEnsembleAt(5); - // kill bookies - killBookie(ensemble.get(0)); - killBookie(ensemble.get(1)); - killBookie(ensemble.get(2)); - - // read multiple entries - LatchListener listener = new LatchListener(0L, numEntries); - ListenerBasedPendingReadOp readOp = createReadOp(lh, 0, numEntries - 1, listener); - readOp.parallelRead(parallelRead).submit(); - listener.expectComplete(); - assertEquals(numEntries, listener.resultCodes.size()); - for (int i = 0; i < numEntries; i++) { - EntryWithRC entry = listener.resultCodes.get((long) i); - assertNotNull(entry); - if (i % 5 == 0) { - assertEquals(BKException.Code.BookieHandleNotAvailableException, entry.rc); - } else { - assertEquals(BKException.Code.OK, entry.rc); - assertEquals(i, Integer.parseInt(new String(entry.entry.getEntry()))); - } - } - - lh.close(); - } - - @Test - public void testReadFailureWithFailedBookiesEnableParallelRead() throws Exception { - readFailureWithFailedBookiesTest(true); - } - - @Test - public void testReadFailureWithFailedBookiesDisableParallelRead() throws Exception { - readFailureWithFailedBookiesTest(false); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedAndEntry.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedAndEntry.java deleted file mode 100644 index 843fa358724..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedAndEntry.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.SortedLedgerStorage; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test reading the last confirmed and entry. - */ -@RunWith(Parameterized.class) -public class TestReadLastConfirmedAndEntry extends BookKeeperClusterTestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestReadLastConfirmedAndEntry.class); - - final BookKeeper.DigestType digestType; - - public TestReadLastConfirmedAndEntry(Class storageClass) { - super(3); - this.digestType = BookKeeper.DigestType.CRC32; - this.baseConf.setAllowEphemeralPorts(false); - this.baseConf.setLedgerStorageClass(storageClass.getName()); - } - - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { - { InterleavedLedgerStorage.class }, - { SortedLedgerStorage.class }, - { DbLedgerStorage.class }, - }); - } - - static class FakeBookie extends TestBookieImpl { - - final long expectedEntryToFail; - final boolean stallOrRespondNull; - - public FakeBookie(ServerConfiguration conf, long expectedEntryToFail, boolean stallOrRespondNull) - throws Exception { - super(conf); - this.expectedEntryToFail = expectedEntryToFail; - this.stallOrRespondNull = stallOrRespondNull; - } - - @Override - public ByteBuf readEntry(long ledgerId, long entryId) - throws IOException, NoLedgerException, BookieException { - if (entryId == expectedEntryToFail) { - if (stallOrRespondNull) { - try { - Thread.sleep(600000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - // ignore - } - } else { - throw new NoEntryException(ledgerId, entryId); - } - } - return super.readEntry(ledgerId, entryId); - } - } - - @Test - public void testAdvancedLacWithEmptyResponse() throws Exception { - byte[] passwd = "advanced-lac-with-empty-response".getBytes(UTF_8); - - ClientConfiguration newConf = new ClientConfiguration(); - newConf.addConfiguration(baseClientConf); - newConf.setAddEntryTimeout(9999999); - newConf.setReadEntryTimeout(9999999); - - // stop existing bookies - stopAllBookies(); - // add fake bookies - long expectedEntryIdToFail = 2; - for (int i = 0; i < numBookies; i++) { - ServerConfiguration conf = newServerConfiguration(); - Bookie b = new FakeBookie(conf, expectedEntryIdToFail, i != 0); - startAndAddBookie(conf, b); - } - - // create bookkeeper - BookKeeper newBk = new BookKeeper(newConf); - // create ledger to write some data - LedgerHandle lh = newBk.createLedger(3, 3, 2, digestType, passwd); - for (int i = 0; i <= expectedEntryIdToFail; i++) { - lh.addEntry("test".getBytes(UTF_8)); - } - - // open ledger to tail reading - LedgerHandle newLh = newBk.openLedgerNoRecovery(lh.getId(), digestType, passwd); - long lac = newLh.readLastConfirmed(); - assertEquals(expectedEntryIdToFail - 1, lac); - Enumeration entries = newLh.readEntries(0, lac); - - int numReads = 0; - long expectedEntryId = 0L; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertEquals(expectedEntryId++, entry.getEntryId()); - ++numReads; - } - assertEquals(lac + 1, numReads); - - final AtomicInteger rcHolder = new AtomicInteger(-12345); - final AtomicLong lacHolder = new AtomicLong(lac); - final AtomicReference entryHolder = new AtomicReference(null); - final CountDownLatch latch = new CountDownLatch(1); - - newLh.asyncReadLastConfirmedAndEntry(newLh.getLastAddConfirmed() + 1, 99999, false, - new AsyncCallback.ReadLastConfirmedAndEntryCallback() { - @Override - public void readLastConfirmedAndEntryComplete(int rc, long lastConfirmed, LedgerEntry entry, Object ctx) { - rcHolder.set(rc); - lacHolder.set(lastConfirmed); - entryHolder.set(entry); - latch.countDown(); - } - }, null); - - lh.addEntry("another test".getBytes(UTF_8)); - - latch.await(); - assertEquals(expectedEntryIdToFail, lacHolder.get()); - assertNull(entryHolder.get()); - assertEquals(BKException.Code.OK, rcHolder.get()); - } - - static class SlowReadLacBookie extends TestBookieImpl { - - private final long lacToSlowRead; - private final CountDownLatch readLatch; - - public SlowReadLacBookie(ServerConfiguration conf, - long lacToSlowRead, CountDownLatch readLatch) - throws Exception { - super(conf); - this.lacToSlowRead = lacToSlowRead; - this.readLatch = readLatch; - } - - @Override - public long readLastAddConfirmed(long ledgerId) throws IOException, BookieException { - long lac = super.readLastAddConfirmed(ledgerId); - logger.info("Last Add Confirmed for ledger {} is {}", ledgerId, lac); - if (lacToSlowRead == lac) { - logger.info("Suspend returning lac {} for ledger {}", lac, ledgerId); - try { - readLatch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - // no-op - } - } - return super.readLastAddConfirmed(ledgerId); - } - } - - static class ReadLastConfirmedAndEntryResult implements AsyncCallback.ReadLastConfirmedAndEntryCallback { - - int rc = -1234; - long lac = -1234L; - LedgerEntry entry = null; - final CountDownLatch doneLatch = new CountDownLatch(1); - - @Override - public void readLastConfirmedAndEntryComplete(int rc, long lastConfirmed, LedgerEntry entry, Object ctx) { - this.rc = rc; - this.lac = lastConfirmed; - this.entry = entry; - doneLatch.countDown(); - } - - void await() throws InterruptedException { - doneLatch.await(); - } - } - - @Test - public void testRaceOnLastAddConfirmed() throws Exception { - byte[] passwd = "race-on-last-add-confirmed".getBytes(UTF_8); - - ClientConfiguration newConf = new ClientConfiguration(); - newConf.addConfiguration(baseClientConf); - newConf.setAddEntryTimeout(9999999); - newConf.setReadEntryTimeout(9999999); - - final long lacToSlowRead = 0L; - final CountDownLatch readLatch = new CountDownLatch(1); - - // stop first bookie - ServerConfiguration bsConf = killBookie(0); - // start it with a slow bookie - Bookie b = new SlowReadLacBookie(bsConf, lacToSlowRead, readLatch); - startAndAddBookie(bsConf, b); - // create bookkeeper - BookKeeper newBk = new BookKeeper(newConf); - // create ledger - LedgerHandle lh = newBk.createLedger(3, 3, 3, digestType, passwd); - // 0) write entry 0 - lh.addEntry("entry-0".getBytes(UTF_8)); - - // open ledger to read - LedgerHandle readLh = newBk.openLedgerNoRecovery(lh.getId(), digestType, passwd); - - // 1) wait entry 0 to be committed - ReadLastConfirmedAndEntryResult readResult = new ReadLastConfirmedAndEntryResult(); - readLh.asyncReadLastConfirmedAndEntry(0L, 9999999, true, readResult, null); - - // 2) write entry 1 to commit entry 0 => lac = 0 - lh.addEntry("entry-1".getBytes(UTF_8)); - readResult.await(); - assertEquals(BKException.Code.OK, readResult.rc); - assertEquals(0L, readResult.lac); - assertEquals(0L, readResult.entry.getEntryId()); - assertEquals("entry-0", new String(readResult.entry.getEntry(), UTF_8)); - - // 3) write entry 2 to commit entry 1 => lac = 1 - lh.addEntry("entry-2".getBytes(UTF_8)); - // 4) count down read latch to trigger previous readLacAndEntry request - readLatch.countDown(); - // 5) due to piggyback, the lac is updated to lac = 1 - while (readLh.getLastAddConfirmed() < 1L) { - Thread.sleep(100); - } - // 6) write entry 3 to commit entry 2 => lac = 2 - lh.addEntry("entry-3".getBytes(UTF_8)); - // 7) readLastConfirmedAndEntry for next entry (we are expecting to read entry 1) - readResult = new ReadLastConfirmedAndEntryResult(); - readLh.asyncReadLastConfirmedAndEntry(1L, 9999999, true, readResult, null); - readResult.await(); - assertEquals(BKException.Code.OK, readResult.rc); - assertEquals(2L, readResult.lac); - assertEquals(1L, readResult.entry.getEntryId()); - assertEquals("entry-1", new String(readResult.entry.getEntry(), UTF_8)); - - lh.close(); - readLh.close(); - - newBk.close(); - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedLongPoll.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedLongPoll.java deleted file mode 100644 index 7633e953fc5..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedLongPoll.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.SortedLedgerStorage; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -/** - * Test read last confirmed long by polling. - */ -@RunWith(Parameterized.class) -public class TestReadLastConfirmedLongPoll extends BookKeeperClusterTestCase { - private static final Logger log = LoggerFactory.getLogger(TestReadLastConfirmedLongPoll.class); - final DigestType digestType; - - public TestReadLastConfirmedLongPoll(Class storageClass) { - super(6); - this.digestType = DigestType.CRC32; - baseConf.setLedgerStorageClass(storageClass.getName()); - } - - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { - { InterleavedLedgerStorage.class }, - { SortedLedgerStorage.class }, - { DbLedgerStorage.class }, - }); - } - - @Test - public void testReadLACLongPollWhenAllBookiesUp() throws Exception { - final int numEntries = 3; - - final LedgerHandle lh = bkc.createLedger(3, 3, 1, digestType, "".getBytes()); - LedgerHandle readLh = bkc.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - // add entries - for (int i = 0; i < (numEntries - 1); i++) { - lh.addEntry(("data" + i).getBytes()); - } - final AtomicBoolean success = new AtomicBoolean(false); - final AtomicInteger numCallbacks = new AtomicInteger(0); - final CountDownLatch firstReadComplete = new CountDownLatch(1); - readLh.asyncTryReadLastConfirmed(new AsyncCallback.ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc) { - success.set(true); - } else { - success.set(false); - } - firstReadComplete.countDown(); - } - }, null); - firstReadComplete.await(); - assertTrue(success.get()); - assertTrue(numCallbacks.get() == 1); - assertEquals(numEntries - 3, readLh.getLastAddConfirmed()); - // try read last confirmed again - success.set(false); - numCallbacks.set(0); - long entryId = readLh.getLastAddConfirmed() + 1; - final CountDownLatch secondReadComplete = new CountDownLatch(1); - readLh.asyncReadLastConfirmedAndEntry(entryId++, 1000, true, - new AsyncCallback.ReadLastConfirmedAndEntryCallback() { - @Override - public void readLastConfirmedAndEntryComplete(int rc, long lastConfirmed, LedgerEntry entry, Object ctx) { - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc && lastConfirmed == (numEntries - 2)) { - success.set(true); - } else { - success.set(false); - } - secondReadComplete.countDown(); - } - }, null); - lh.addEntry(("data" + (numEntries - 1)).getBytes()); - secondReadComplete.await(); - assertTrue(success.get()); - assertTrue(numCallbacks.get() == 1); - assertEquals(numEntries - 2, readLh.getLastAddConfirmed()); - - success.set(false); - numCallbacks.set(0); - final CountDownLatch thirdReadComplete = new CountDownLatch(1); - readLh.asyncReadLastConfirmedAndEntry(entryId++, 1000, false, - new AsyncCallback.ReadLastConfirmedAndEntryCallback() { - @Override - public void readLastConfirmedAndEntryComplete(int rc, long lastConfirmed, LedgerEntry entry, Object ctx) { - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc && lastConfirmed == (numEntries - 1)) { - success.set(true); - } else { - success.set(false); - } - thirdReadComplete.countDown(); - } - }, null); - lh.addEntry(("data" + numEntries).getBytes()); - thirdReadComplete.await(); - assertTrue(success.get()); - assertTrue(numCallbacks.get() == 1); - assertEquals(numEntries - 1, readLh.getLastAddConfirmed()); - lh.close(); - readLh.close(); - } - - @Test - public void testReadLACLongPollWhenSomeBookiesDown() throws Exception { - final int numEntries = 3; - final LedgerHandle lh = bkc.createLedger(3, 1, 1, digestType, "".getBytes()); - LedgerHandle readLh = bkc.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - // add entries - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + i).getBytes()); - } - for (int i = 0; i < numEntries; i++) { - ServerConfiguration[] confs = new ServerConfiguration[numEntries - 1]; - for (int j = 0; j < numEntries - 1; j++) { - int idx = (i + 1 + j) % numEntries; - confs[j] = killBookie(LedgerMetadataUtils.getLastEnsembleValue(lh.getLedgerMetadata()).get(idx)); - } - - final AtomicBoolean entryAsExpected = new AtomicBoolean(false); - final AtomicBoolean success = new AtomicBoolean(false); - final AtomicInteger numCallbacks = new AtomicInteger(0); - final CountDownLatch readComplete = new CountDownLatch(1); - final int entryId = i; - readLh.asyncTryReadLastConfirmed(new AsyncCallback.ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc) { - success.set(true); - entryAsExpected.set(lastConfirmed == (entryId - 1)); - } else { - System.out.println("Return value" + rc); - success.set(false); - entryAsExpected.set(false); - } - readComplete.countDown(); - } - }, null); - readComplete.await(); - assertTrue(success.get()); - assertTrue(entryAsExpected.get()); - assertTrue(numCallbacks.get() == 1); - - lh.close(); - readLh.close(); - - // start the bookies - for (ServerConfiguration conf : confs) { - startAndAddBookie(conf); - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastEntry.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastEntry.java deleted file mode 100644 index 0748d30350f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastEntry.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.Arrays; -import java.util.Enumeration; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Test read next entry and the latest last add confirmed. - */ -public class TestReadLastEntry extends BookKeeperClusterTestCase { - - final DigestType digestType; - - public TestReadLastEntry() { - super(1); - this.digestType = DigestType.CRC32; - } - - @Test - public void testTryReadLastEntryAsyncOnEmptyLedger() throws Exception { - final LedgerHandle lh = bkc.createLedger(1, 1, 1, digestType, "".getBytes()); - lh.close(); - - LedgerHandle readLh = bkc.openLedger(lh.getId(), digestType, "".getBytes()); - - final CountDownLatch latch1 = new CountDownLatch(1); - final AtomicInteger rcStore = new AtomicInteger(); - readLh.asyncReadLastEntry(new ReadCallback() { - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - rcStore.set(rc); - latch1.countDown(); - } - }, null); - - latch1.await(); - - assertEquals(BKException.Code.NoSuchEntryException, rcStore.get()); - - lh.close(); - readLh.close(); - } - - @Test - public void testTryReadLastEntryOnEmptyLedger() throws Exception { - final LedgerHandle lh = bkc.createLedger(1, 1, 1, digestType, "".getBytes()); - lh.close(); - - LedgerHandle readLh = bkc.openLedger(lh.getId(), digestType, "".getBytes()); - try { - LedgerEntry lastEntry = readLh.readLastEntry(); - fail("should fail with NoSuchEntryException"); - } catch (BKException e) { - assertEquals(e.getCode(), Code.NoSuchEntryException); - } - - lh.close(); - readLh.close(); - } - - @Test - public void testTryReadLastEntryAsync() throws Exception { - final LedgerHandle lh = bkc.createLedger(1, 1, 1, digestType, "".getBytes()); - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'x'); - for (int j = 0; j < 100; j++) { - data[1023] = Integer.valueOf(j).byteValue(); - lh.addEntry(data); - } - lh.close(); - - LedgerHandle readLh = bkc.openLedger(lh.getId(), digestType, "".getBytes()); - final CountDownLatch latch1 = new CountDownLatch(1); - final AtomicInteger rcStore = new AtomicInteger(); - final AtomicInteger lastByteStore = new AtomicInteger(); - - readLh.asyncReadLastEntry(new ReadCallback() { - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - rcStore.set(rc); - LedgerEntry entry = seq.nextElement(); - lastByteStore.set(entry.getEntry()[1023]); - latch1.countDown(); - } - }, null); - - latch1.await(); - - assertEquals(BKException.Code.OK, rcStore.get()); - assertEquals(lastByteStore.byteValue(), data[1023]); - - lh.close(); - readLh.close(); - } - - @Test - public void testTryReadLastEntrySync() throws Exception { - final LedgerHandle lh = bkc.createLedger(1, 1, 1, digestType, "".getBytes()); - byte[] data = new byte[1024]; - Arrays.fill(data, (byte) 'x'); - for (int j = 0; j < 100; j++) { - data[1023] = Integer.valueOf(j).byteValue(); - lh.addEntry(data); - } - lh.close(); - - LedgerHandle readLh = bkc.openLedger(lh.getId(), digestType, "".getBytes()); - LedgerEntry lastEntry = readLh.readLastEntry(); - - assertEquals(lastEntry.getEntry()[1023], Integer.valueOf(99).byteValue()); - - lh.close(); - readLh.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadTimeout.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadTimeout.java deleted file mode 100644 index 160741b97d2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadTimeout.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This unit test tests ledger fencing. - * - */ -public class TestReadTimeout extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestReadTimeout.class); - - DigestType digestType; - - public TestReadTimeout() { - super(10); - this.digestType = DigestType.CRC32; - } - - @SuppressWarnings("deprecation") - @Test - public void testReadTimeout() throws Exception { - final AtomicBoolean completed = new AtomicBoolean(false); - - LedgerHandle writelh = bkc.createLedger(3, 3, digestType, "testPasswd".getBytes()); - String tmp = "Foobar"; - - final int numEntries = 10; - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(tmp.getBytes()); - } - - Set beforeSet = new HashSet(); - beforeSet.addAll(writelh.getLedgerMetadata().getEnsembleAt(numEntries)); - - final BookieId bookieToSleep = writelh.getLedgerMetadata().getEnsembleAt(numEntries).get(0); - int sleeptime = baseClientConf.getReadTimeout() * 3; - CountDownLatch latch = sleepBookie(bookieToSleep, sleeptime); - latch.await(); - - writelh.asyncAddEntry(tmp.getBytes(), - new AddCallback() { - public void addComplete(int rc, LedgerHandle lh, - long entryId, Object ctx) { - completed.set(true); - } - }, null); - Thread.sleep((baseClientConf.getReadTimeout() * 3) * 1000); - Assert.assertTrue("Write request did not finish", completed.get()); - - Set afterSet = new HashSet(); - afterSet.addAll(writelh.getLedgerMetadata().getEnsembleAt(numEntries + 1)); - beforeSet.removeAll(afterSet); - Assert.assertTrue("Bookie set should not match", beforeSet.size() != 0); - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRegionAwareEnsemblePlacementPolicy.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRegionAwareEnsemblePlacementPolicy.java deleted file mode 100644 index 4f5bf086215..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRegionAwareEnsemblePlacementPolicy.java +++ /dev/null @@ -1,2049 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.RegionAwareEnsemblePlacementPolicy - .REPP_DISALLOW_BOOKIE_PLACEMENT_IN_REGION_FEATURE_NAME; -import static org.apache.bookkeeper.client.RegionAwareEnsemblePlacementPolicy.REPP_DNS_RESOLVER_CLASS; -import static org.apache.bookkeeper.client.RegionAwareEnsemblePlacementPolicy - .REPP_ENABLE_DURABILITY_ENFORCEMENT_IN_REPLACE; -import static org.apache.bookkeeper.client.RegionAwareEnsemblePlacementPolicy.REPP_ENABLE_VALIDATION; -import static org.apache.bookkeeper.client.RegionAwareEnsemblePlacementPolicy.REPP_MINIMUM_REGIONS_FOR_DURABILITY; -import static org.apache.bookkeeper.client.RegionAwareEnsemblePlacementPolicy.REPP_REGIONS_TO_WRITE; -import static org.apache.bookkeeper.client.RoundRobinDistributionSchedule.writeSetFromValues; -import static org.apache.bookkeeper.feature.SettableFeatureProvider.DISABLE_ALL; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.netty.util.HashedWheelTimer; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; -import org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.feature.FeatureProvider; -import org.apache.bookkeeper.feature.SettableFeature; -import org.apache.bookkeeper.feature.SettableFeatureProvider; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.bookkeeper.net.NetworkTopology; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test a region-aware ensemble placement policy. - */ -public class TestRegionAwareEnsemblePlacementPolicy extends TestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestRegionAwareEnsemblePlacementPolicy.class); - - RegionAwareEnsemblePlacementPolicy repp; - final ClientConfiguration conf = new ClientConfiguration(); - final ArrayList ensemble = new ArrayList(); - DistributionSchedule.WriteSet writeSet = DistributionSchedule.NULL_WRITE_SET; - BookieSocketAddress addr1; - BookieSocketAddress addr2, addr3, addr4; - HashedWheelTimer timer; - - static void updateMyRack(String rack) throws Exception { - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostAddress(), rack); - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostName(), rack); - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getCanonicalHostName(), rack); - BookieSocketAddress bookieAddress = new BookieSocketAddress( - InetAddress.getLocalHost().getHostAddress(), 0); - StaticDNSResolver.addNodeToRack(bookieAddress.getSocketAddress().getHostName(), rack); - StaticDNSResolver.addNodeToRack(bookieAddress.getSocketAddress().getAddress().getHostAddress(), rack); - StaticDNSResolver.addNodeToRack("127.0.0.1", rack); - StaticDNSResolver.addNodeToRack("localhost", rack); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - StaticDNSResolver.reset(); - updateMyRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - LOG.info("Set up static DNS Resolver."); - conf.setProperty(REPP_DNS_RESOLVER_CLASS, StaticDNSResolver.class.getName()); - - addr1 = new BookieSocketAddress("127.0.0.2", 3181); - addr2 = new BookieSocketAddress("127.0.0.3", 3181); - addr3 = new BookieSocketAddress("127.0.0.4", 3181); - addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/r1/rack1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/r1/rack2"); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - ensemble.add(addr4.toBookieId()); - - writeSet = writeSetFromValues(0, 1, 2, 3); - - timer = new HashedWheelTimer( - new ThreadFactoryBuilder().setNameFormat("TestTimer-%d").build(), - conf.getTimeoutTimerTickDurationMs(), TimeUnit.MILLISECONDS, - conf.getTimeoutTimerNumTicks()); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - } - - @Override - protected void tearDown() throws Exception { - repp.uninitalize(); - super.tearDown(); - } - - static BookiesHealthInfo getBookiesHealthInfo() { - return getBookiesHealthInfo(new HashMap<>(), new HashMap<>()); - } - - static BookiesHealthInfo getBookiesHealthInfo(Map bookieFailureHistory, - Map bookiePendingRequests) { - return new BookiesHealthInfo() { - @Override - public long getBookieFailureHistory(BookieId bookieSocketAddress) { - return bookieFailureHistory.getOrDefault(bookieSocketAddress, -1L); - } - - @Override - public long getBookiePendingRequests(BookieId bookieSocketAddress) { - return bookiePendingRequests.getOrDefault(bookieSocketAddress, 0L); - } - }; - } - - - @Test - public void testNotReorderReadIfInDefaultRack() throws Exception { - repp.uninitalize(); - updateMyRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - assertEquals(origWriteSet, reorderSet); - } - - @Test - public void testNodeInSameRegion() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack3"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // make sure we've detected the right region - assertEquals("r1", repp.myRegion); - - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet.copy()); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(0, 3, 1, 2); - LOG.info("write set : {}", writeSet); - LOG.info("reorder set : {}", reorderSet); - LOG.info("expected set : {}", expectedSet); - LOG.info("reorder equals {}", reorderSet.equals(writeSet)); - assertFalse(reorderSet.equals(writeSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeNotInSameRegions() throws Exception { - repp.uninitalize(); - updateMyRack("/r2/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - LOG.info("reorder set : {}", reorderSet); - assertEquals(origWriteSet, reorderSet); - } - - @Test - public void testNodeDown() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 1, 2, 0); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeReadOnly() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - Set ro = new HashSet(); - ro.add(addr1.toBookieId()); - repp.onClusterChanged(addrs, ro); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 1, 2, 0); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - repp.registerSlowBookie(addr1.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); - repp.onClusterChanged(addrs, new HashSet<>()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 1, 2, 0); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testTwoNodesSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - repp.registerSlowBookie(addr1.toBookieId(), 0L); - repp.registerSlowBookie(addr2.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); - bookiePendingMap.put(addr2.toBookieId(), 2L); - repp.onClusterChanged(addrs, new HashSet<>()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 2, 0, 1); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testTwoNodesDown() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - addrs.remove(addr2.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 2, 0, 1); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeDownAndNodeSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - repp.registerSlowBookie(addr1.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr1.toBookieId(), 1L); - addrs.remove(addr2.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 2, 0, 1); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testNodeDownAndReadOnlyAndNodeSlow() throws Exception { - repp.uninitalize(); - updateMyRack("/r1/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - addrs.remove(addr1.toBookieId()); - addrs.remove(addr2.toBookieId()); - Set ro = new HashSet<>(); - ro.add(addr2.toBookieId()); - repp.registerSlowBookie(addr3.toBookieId(), 0L); - Map bookiePendingMap = new HashMap<>(); - bookiePendingMap.put(addr3.toBookieId(), 1L); - repp.onClusterChanged(addrs, ro); - - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet reorderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(new HashMap<>(), bookiePendingMap), writeSet); - DistributionSchedule.WriteSet expectedSet = writeSetFromValues(3, 1, 2, 0); - LOG.info("reorder set : {}", reorderSet); - assertFalse(reorderSet.equals(origWriteSet)); - assertEquals(expectedSet, reorderSet); - } - - @Test - public void testReplaceBookieWithEnoughBookiesInSameRegion() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/default-region/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - BookieId replacedBookie = repp.replaceBookie(1, 1, 1, null, - new ArrayList(), addr2.toBookieId(), new HashSet()).getResult(); - assertEquals(addr3.toBookieId(), replacedBookie); - } - - @Test - public void testReplaceBookieWithEnoughBookiesInDifferentRegion() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region3/r4"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - BookieId replacedBookie = repp.replaceBookie(1, 1, 1, null, - new ArrayList(), addr2.toBookieId(), excludedAddrs).getResult(); - - assertFalse(addr1.toBookieId().equals(replacedBookie)); - assertTrue(addr3.toBookieId().equals(replacedBookie) - || addr4.toBookieId().equals(replacedBookie)); - } - - @Test - public void testNewEnsembleBookieWithNotEnoughBookies() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region3/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region4/r4"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List list = repp.newEnsemble(5, 5, 3, null, - new HashSet()).getResult(); - LOG.info("Ensemble : {}", list); - fail("Should throw BKNotEnoughBookiesException when there is not enough bookies"); - } catch (BKNotEnoughBookiesException bnebe) { - // should throw not enou - } - } - - @Test - public void testNewEnsembleBookieWithOneEmptyRegion() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region3/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region4/r4"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - - Field logField = repp.getClass().getDeclaredField("LOG"); - Logger mockLogger = mock(Logger.class); - - Field modifiers = Field.class.getDeclaredField("modifiers"); - modifiers.setAccessible(true); - modifiers.setInt(logField, logField.getModifiers() & ~Modifier.FINAL); - logField.setAccessible(true); - logField.set(null, mockLogger); - - repp.onClusterChanged(addrs, new HashSet()); - repp.newEnsemble(3, 3, 3, null, - new HashSet()).getResult(); - verify(mockLogger, times(0)).warn("Could not allocate {} bookies in region {}, try allocating {} bookies", - 1, "UnknownRegion", 0); - addrs = new HashSet(); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - repp.newEnsemble(3, 3, 3, null, - new HashSet()).getResult(); - - verify(mockLogger, times(0)).warn("Could not allocate {} bookies in region {}, try allocating {} bookies", - 1, "UnknownRegion", 0); - } - - @Test - public void testReplaceBookieWithNotEnoughBookies() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region3/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region4/r4"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - // replace node under r2 - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr1.toBookieId()); - excludedAddrs.add(addr3.toBookieId()); - excludedAddrs.add(addr4.toBookieId()); - try { - repp.replaceBookie(1, 1, 1, null, new ArrayList(), addr2.toBookieId(), excludedAddrs); - fail("Should throw BKNotEnoughBookiesException when there is not enough bookies"); - } catch (BKNotEnoughBookiesException bnebe) { - // should throw not enou - } - } - - @Test - public void testNewEnsembleWithSingleRegion() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region1/r2"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List ensemble = repp.newEnsemble(3, 2, 2, null, - new HashSet()).getResult(); - assertEquals(0, getNumCoveredRegionsInWriteQuorum(ensemble, 2)); - List ensemble2 = repp.newEnsemble(4, 2, 2, null, - new HashSet()).getResult(); - assertEquals(0, getNumCoveredRegionsInWriteQuorum(ensemble2, 2)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testNewEnsembleWithMultipleRegions() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_REGION_AND_RACK); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region1/r2"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List ensemble = repp.newEnsemble(3, 2, 2, null, - new HashSet()).getResult(); - int numCovered = getNumCoveredRegionsInWriteQuorum(ensemble, 2); - assertTrue(numCovered >= 1); - assertTrue(numCovered < 3); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - try { - List ensemble2 = repp.newEnsemble(4, 2, 2, null, - new HashSet()).getResult(); - int numCovered = getNumCoveredRegionsInWriteQuorum(ensemble2, 2); - assertTrue(numCovered >= 1 && numCovered < 3); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testNewEnsembleWithPickDifferentRack() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setMinNumRacksPerWriteQuorum(2); - clientConf.setEnforceMinNumFaultDomainsForWrite(false); - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region-1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region-1/r1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region-1/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region-1/r3"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region-2/r1"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - int ensembleSize = 4; - int writeQuorumSize = 4; - int ackQuorumSize = 2; - - Set excludeBookies = new HashSet<>(); - - for (int i = 0; i < 50; ++i) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - if (ensemble.contains(addr1.toBookieId()) && ensemble.contains(addr2.toBookieId())) { - fail("addr1 and addr2 is same rack."); - } - } - - //addr4 shutdown. - addrs.remove(addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - for (int i = 0; i < 50; ++i) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - assertTrue(ensemble.contains(addr1.toBookieId()) && ensemble.contains(addr2.toBookieId())); - } - } - - @Test - public void testNewEnsembleWithEnoughRegions() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/default-region/default-rack1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region3/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/default-region/default-rack2"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region1/r12"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region2/r13"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region3/r14"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List ensemble1 = repp.newEnsemble(3, 2, 2, null, - new HashSet()).getResult(); - assertEquals(3, getNumCoveredRegionsInWriteQuorum(ensemble1, 2)); - List ensemble2 = repp.newEnsemble(4, 2, 2, null, - new HashSet()).getResult(); - assertEquals(4, getNumCoveredRegionsInWriteQuorum(ensemble2, 2)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testNewEnsembleWithMultipleRacksWithCommonRack() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(conf); - clientConf.setEnforceMinNumRacksPerWriteQuorum(true); - clientConf.setMinNumRacksPerWriteQuorum(3); - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(clientConf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.10", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region1/r3"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region2/r1"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/region3/r1"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - addrs.add(addr10.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - try { - int ensembleSize = 10; - int writeQuorumSize = 10; - int ackQuorumSize = 2; - - for (int i = 0; i < 50; ++i) { - Set excludeBookies = new HashSet<>(); - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - } - } catch (Exception e) { - fail("RegionAwareEnsemblePlacementPolicy should newEnsemble succeed."); - } - } - - @Test - public void testNewEnsembleWithThreeRegions() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region2/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region3/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region1/r11"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region1/r12"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region2/r13"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region3/r14"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region2/r23"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/region1/r24"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - addrs.add(addr10.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - List ensemble = repp.newEnsemble(6, 6, 4, null, - new HashSet()).getResult(); - assert(ensemble.contains(addr4.toBookieId())); - assert(ensemble.contains(addr8.toBookieId())); - assert(ensemble.size() == 6); - assertEquals(3, getNumRegionsInEnsemble(ensemble)); - ensemble = repp.newEnsemble(7, 7, 4, null, new HashSet()).getResult(); - assert(ensemble.contains(addr4.toBookieId())); - assert(ensemble.contains(addr8.toBookieId())); - assert(ensemble.size() == 7); - assertEquals(3, getNumRegionsInEnsemble(ensemble)); - ensemble = repp.newEnsemble(8, 8, 5, null, new HashSet()).getResult(); - assert(ensemble.contains(addr4.toBookieId())); - assert(ensemble.contains(addr8.toBookieId())); - assert(ensemble.size() == 8); - assertEquals(3, getNumRegionsInEnsemble(ensemble)); - ensemble = repp.newEnsemble(9, 9, 5, null, new HashSet()).getResult(); - assert(ensemble.contains(addr4.toBookieId())); - assert(ensemble.contains(addr8.toBookieId())); - assert(ensemble.size() == 9); - assertEquals(3, getNumRegionsInEnsemble(ensemble)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testNewEnsembleWithThreeRegionsWithDisable() throws Exception { - FeatureProvider featureProvider = new SettableFeatureProvider("", 0); - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - conf.setProperty(REPP_DISALLOW_BOOKIE_PLACEMENT_IN_REGION_FEATURE_NAME, "disallowBookies"); - repp.initialize(conf, Optional.empty(), timer, featureProvider, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region2/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region3/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region1/r11"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region1/r12"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region2/r13"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region3/r14"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region2/r23"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/region1/r24"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - addrs.add(addr10.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - try { - ((SettableFeature) featureProvider.scope("region1").getFeature("disallowBookies")).set(true); - List ensemble = repp.newEnsemble(6, 6, 4, null, - new HashSet()).getResult(); - assertEquals(2, getNumRegionsInEnsemble(ensemble)); - assert(ensemble.contains(addr1.toBookieId())); - assert(ensemble.contains(addr3.toBookieId())); - assert(ensemble.contains(addr4.toBookieId())); - assert(ensemble.contains(addr7.toBookieId())); - assert(ensemble.contains(addr8.toBookieId())); - assert(ensemble.contains(addr9.toBookieId())); - assert(ensemble.size() == 6); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - try { - ((SettableFeature) featureProvider.scope("region2").getFeature("disallowBookies")).set(true); - repp.newEnsemble(6, 6, 4, null, new HashSet()); - fail("Should get not enough bookies exception even there is only one region with insufficient bookies."); - } catch (BKNotEnoughBookiesException bnebe) { - // Expected - } - try { - ((SettableFeature) featureProvider.scope("region2").getFeature("disallowBookies")).set(false); - List ensemble = repp.newEnsemble(6, 6, 4, null, - new HashSet()).getResult(); - assert(ensemble.contains(addr1.toBookieId())); - assert(ensemble.contains(addr3.toBookieId())); - assert(ensemble.contains(addr4.toBookieId())); - assert(ensemble.contains(addr7.toBookieId())); - assert(ensemble.contains(addr8.toBookieId())); - assert(ensemble.contains(addr9.toBookieId())); - assert(ensemble.size() == 6); - assertEquals(2, getNumRegionsInEnsemble(ensemble)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - - @Test - public void testNewEnsembleWithFiveRegions() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - conf.setProperty(REPP_REGIONS_TO_WRITE, "region1;region2;region3;region4;region5"); - conf.setProperty(REPP_MINIMUM_REGIONS_FOR_DURABILITY, 5); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.1.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.1.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.1.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.1.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.1.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.1.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.1.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.1.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.1.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.1.0.11", 3181); - BookieSocketAddress addr11 = new BookieSocketAddress("127.1.0.12", 3181); - BookieSocketAddress addr12 = new BookieSocketAddress("127.1.0.13", 3181); - BookieSocketAddress addr13 = new BookieSocketAddress("127.1.0.14", 3181); - BookieSocketAddress addr14 = new BookieSocketAddress("127.1.0.15", 3181); - BookieSocketAddress addr15 = new BookieSocketAddress("127.1.0.16", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region2/r11"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region2/r12"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region3/r13"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region3/r14"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region3/r23"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/region4/r24"); - StaticDNSResolver.addNodeToRack(addr11.getHostName(), "/region4/r31"); - StaticDNSResolver.addNodeToRack(addr12.getHostName(), "/region4/r32"); - StaticDNSResolver.addNodeToRack(addr13.getHostName(), "/region5/r33"); - StaticDNSResolver.addNodeToRack(addr14.getHostName(), "/region5/r34"); - StaticDNSResolver.addNodeToRack(addr15.getHostName(), "/region5/r35"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - addrs.add(addr10.toBookieId()); - addrs.add(addr11.toBookieId()); - addrs.add(addr12.toBookieId()); - addrs.add(addr13.toBookieId()); - addrs.add(addr14.toBookieId()); - addrs.add(addr15.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - try { - List ensemble = repp.newEnsemble(10, 10, 10, null, - new HashSet()).getResult(); - assert(ensemble.size() == 10); - assertEquals(5, getNumRegionsInEnsemble(ensemble)); - } catch (BKNotEnoughBookiesException bnebe) { - LOG.error("BKNotEnoughBookiesException", bnebe); - fail("Should not get not enough bookies exception even there is only one rack."); - } - - try { - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr10.toBookieId()); - List ensemble = repp.newEnsemble(10, 10, 10, null, - excludedAddrs).getResult(); - assert(ensemble.contains(addr11.toBookieId()) && ensemble.contains(addr12.toBookieId())); - assert(ensemble.size() == 10); - assertEquals(5, getNumRegionsInEnsemble(ensemble)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testEnsembleWithThreeRegionsReplace() throws Exception { - testEnsembleWithThreeRegionsReplaceInternal(3, false, false); - } - - @Test - public void testEnsembleWithThreeRegionsReplaceDisableOneRegion() throws Exception { - testEnsembleWithThreeRegionsReplaceInternal(2, false, true); - } - - @Test - public void testEnsembleWithThreeRegionsReplaceMinDurabilityOne() throws Exception { - testEnsembleWithThreeRegionsReplaceInternal(1, false, false); - } - - @Test - public void testEnsembleWithThreeRegionsReplaceDisableDurability() throws Exception { - testEnsembleWithThreeRegionsReplaceInternal(1, true, false); - } - - public void testEnsembleWithThreeRegionsReplaceInternal(int minDurability, boolean disableDurability, - boolean disableOneRegion) throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - conf.setProperty(REPP_REGIONS_TO_WRITE, "region1;region2;region3"); - conf.setProperty(REPP_MINIMUM_REGIONS_FOR_DURABILITY, minDurability); - FeatureProvider featureProvider = new SettableFeatureProvider("", 0); - if (minDurability <= 1) { - conf.setProperty(REPP_ENABLE_DURABILITY_ENFORCEMENT_IN_REPLACE, false); - } else { - conf.setProperty(REPP_ENABLE_DURABILITY_ENFORCEMENT_IN_REPLACE, true); - } - conf.setProperty(REPP_DISALLOW_BOOKIE_PLACEMENT_IN_REGION_FEATURE_NAME, "disallowBookies"); - - repp.initialize(conf, Optional.empty(), timer, featureProvider, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.1.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.1.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.1.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.1.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.1.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.1.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.1.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.1.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.1.0.10", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region2/r11"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region2/r12"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region3/r13"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region3/r14"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region3/r23"); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - SettableFeature disableDurabilityFeature = - (SettableFeature) featureProvider.getFeature( - BookKeeperConstants.FEATURE_REPP_DISABLE_DURABILITY_ENFORCEMENT); - - if (disableDurability) { - disableDurabilityFeature.set(true); - } - - int ackQuorum = 4; - if (minDurability > 2) { - ackQuorum = 5; - } - - List ensemble; - try { - ensemble = repp.newEnsemble(6, 6, ackQuorum, null, new HashSet()).getResult(); - assert(ensemble.size() == 6); - assertEquals(3, getNumRegionsInEnsemble(ensemble)); - } catch (BKNotEnoughBookiesException bnebe) { - LOG.error("BKNotEnoughBookiesException", bnebe); - fail("Should not get not enough bookies exception even there is only one rack."); - throw bnebe; - } - - if (disableOneRegion) { - ((SettableFeature) featureProvider.scope("region2").getFeature("disallowBookies")).set(true); - Set region2Bookies = new HashSet(); - region2Bookies.add(addr4.toBookieId()); - region2Bookies.add(addr5.toBookieId()); - region2Bookies.add(addr6.toBookieId()); - Set region1And3Bookies = new HashSet(addrs); - region1And3Bookies.removeAll(region2Bookies); - - Set excludedAddrs = new HashSet(); - for (BookieId addr: region2Bookies) { - if (ensemble.contains(addr)) { - BookieId replacedBookie = repp.replaceBookie(6, 6, ackQuorum, null, - ensemble, addr, excludedAddrs).getResult(); - ensemble.remove(addr); - ensemble.add(replacedBookie); - } - } - assertEquals(2, getNumRegionsInEnsemble(ensemble)); - assertTrue(ensemble.containsAll(region1And3Bookies)); - } else { - BookieId bookieToReplace; - BookieId replacedBookieExpected; - if (ensemble.contains(addr4.toBookieId())) { - bookieToReplace = addr4.toBookieId(); - if (ensemble.contains(addr5.toBookieId())) { - replacedBookieExpected = addr6.toBookieId(); - } else { - replacedBookieExpected = addr5.toBookieId(); - } - } else { - replacedBookieExpected = addr4.toBookieId(); - bookieToReplace = addr5.toBookieId(); - } - Set excludedAddrs = new HashSet(); - - try { - BookieId replacedBookie = repp.replaceBookie(6, 6, ackQuorum, null, - ensemble, bookieToReplace, excludedAddrs).getResult(); - assert (replacedBookie.equals(replacedBookieExpected)); - assertEquals(3, getNumRegionsInEnsemble(ensemble)); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - - excludedAddrs.add(replacedBookieExpected); - try { - repp.replaceBookie(6, 6, ackQuorum, null, ensemble, bookieToReplace, excludedAddrs); - if (minDurability > 1 && !disableDurabilityFeature.isAvailable()) { - fail("Should throw BKNotEnoughBookiesException when there is not enough bookies"); - } - } catch (BKNotEnoughBookiesException bnebe) { - if (minDurability <= 1 || disableDurabilityFeature.isAvailable()) { - fail("Should not throw BKNotEnoughBookiesException when there is not enough bookies"); - } - } - } - } - - @Test - public void testEnsembleMinDurabilityOne() throws Exception { - testEnsembleDurabilityDisabledInternal(1, false); - } - - @Test - public void testEnsembleDisableDurability() throws Exception { - testEnsembleDurabilityDisabledInternal(2, true); - } - - public void testEnsembleDurabilityDisabledInternal(int minDurability, boolean disableDurability) throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - conf.setProperty(REPP_REGIONS_TO_WRITE, "region1;region2;region3"); - conf.setProperty(REPP_MINIMUM_REGIONS_FOR_DURABILITY, minDurability); - FeatureProvider featureProvider = new SettableFeatureProvider("", 0); - if (minDurability <= 1) { - conf.setProperty(REPP_ENABLE_DURABILITY_ENFORCEMENT_IN_REPLACE, false); - } else { - conf.setProperty(REPP_ENABLE_DURABILITY_ENFORCEMENT_IN_REPLACE, true); - } - - repp.initialize(conf, Optional.empty(), timer, featureProvider, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.1.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.1.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.1.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.1.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.1.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.1.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.1.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.1.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.1.0.10", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region1/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region1/r11"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region1/r12"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region1/r13"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region1/r14"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region1/r23"); - - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - if (disableDurability) { - ((SettableFeature) featureProvider.getFeature( - BookKeeperConstants.FEATURE_REPP_DISABLE_DURABILITY_ENFORCEMENT)) - .set(true); - } - - List ensemble; - try { - ensemble = repp.newEnsemble(6, 6, 4, null, new HashSet()).getResult(); - assert(ensemble.size() == 6); - } catch (BKNotEnoughBookiesException bnebe) { - LOG.error("BKNotEnoughBookiesException", bnebe); - fail("Should not get not enough bookies exception even there is only one rack."); - throw bnebe; - } - - Set excludedAddrs = new HashSet(); - - try { - repp.replaceBookie(6, 6, 4, null, ensemble, ensemble.get(2), excludedAddrs); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testNewEnsembleFailWithFiveRegions() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - conf.setProperty(REPP_REGIONS_TO_WRITE, "region1;region2;region3;region4;region5"); - conf.setProperty(REPP_MINIMUM_REGIONS_FOR_DURABILITY, 5); - conf.setProperty(REPP_ENABLE_VALIDATION, false); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region3/r11"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region3/r12"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region4/r13"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region4/r14"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region5/r23"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/region5/r24"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - addrs.add(addr10.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - Set excludedAddrs = new HashSet(); - excludedAddrs.add(addr10.toBookieId()); - excludedAddrs.add(addr9.toBookieId()); - try { - LOG.info("Ensemble : {}", repp.newEnsemble(5, 5, 5, null, excludedAddrs).getResult()); - fail("Should throw BKNotEnoughBookiesException when there is not enough bookies"); - } catch (BKNotEnoughBookiesException bnebe) { - // should throw not enou - } - } - - private void prepareNetworkTopologyForReorderTests(String myRegion) throws Exception { - repp.uninitalize(); - updateMyRack("/" + myRegion); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region1/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/r1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region2/r3"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region3/r1"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region3/r2"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region3/r3"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - } - - @Test - public void testBasicReorderReadSequenceWithLocalRegion() throws Exception { - basicReorderReadSequenceWithLocalRegionTest("region2", false); - } - - @Test - public void testBasicReorderReadLACSequenceWithLocalRegion() throws Exception { - basicReorderReadSequenceWithLocalRegionTest("region2", true); - } - - private void basicReorderReadSequenceWithLocalRegionTest(String myRegion, boolean isReadLAC) throws Exception { - prepareNetworkTopologyForReorderTests(myRegion); - List ensemble = repp.newEnsemble(9, 9, 5, null, - new HashSet()).getResult(); - assertEquals(9, getNumCoveredRegionsInWriteQuorum(ensemble, 9)); - - DistributionSchedule ds = new RoundRobinDistributionSchedule(9, 9, 9); - - LOG.info("My region is {}, ensemble : {}", repp.myRegion, ensemble); - - int ensembleSize = ensemble.size(); - for (int i = 0; i < ensembleSize; i++) { - DistributionSchedule.WriteSet writeSet = ds.getWriteSet(i); - DistributionSchedule.WriteSet origWriteSet = writeSet.copy(); - DistributionSchedule.WriteSet readSet; - if (isReadLAC) { - readSet = repp.reorderReadLACSequence( - ensemble, - getBookiesHealthInfo(), writeSet); - } else { - readSet = repp.reorderReadSequence( - ensemble, - getBookiesHealthInfo(), writeSet); - } - - LOG.info("Reorder {} => {}.", origWriteSet, readSet); - - // first few nodes less than REMOTE_NODE_IN_REORDER_SEQUENCE should be local region - int k = 0; - for (; k < RegionAwareEnsemblePlacementPolicy.REMOTE_NODE_IN_REORDER_SEQUENCE; k++) { - BookieId address = ensemble.get(readSet.get(k)); - assertEquals(myRegion, StaticDNSResolver.getRegion(repp.bookieAddressResolver - .resolve(address).getHostName())); - } - BookieId remoteAddress = ensemble.get(readSet.get(k)); - assertFalse(myRegion.equals(StaticDNSResolver.getRegion(repp.bookieAddressResolver - .resolve(remoteAddress).getHostName()))); - k++; - BookieId localAddress = ensemble.get(readSet.get(k)); - assertEquals(myRegion, StaticDNSResolver.getRegion(repp.bookieAddressResolver - .resolve(localAddress).getHostName())); - k++; - for (; k < ensembleSize; k++) { - BookieId address = ensemble.get(readSet.get(k)); - assertFalse(myRegion.equals(StaticDNSResolver.getRegion(repp.bookieAddressResolver - .resolve(address).getHostName()))); - } - } - } - - @Test - public void testBasicReorderReadSequenceWithRemoteRegion() throws Exception { - basicReorderReadSequenceWithRemoteRegionTest("region4", false); - } - - @Test - public void testBasicReorderReadLACSequenceWithRemoteRegion() throws Exception { - basicReorderReadSequenceWithRemoteRegionTest("region4", true); - } - - private void basicReorderReadSequenceWithRemoteRegionTest(String myRegion, boolean isReadLAC) throws Exception { - prepareNetworkTopologyForReorderTests(myRegion); - - List ensemble = repp.newEnsemble(9, 9, 5, null, - new HashSet()).getResult(); - assertEquals(9, getNumCoveredRegionsInWriteQuorum(ensemble, 9)); - - DistributionSchedule ds = new RoundRobinDistributionSchedule(9, 9, 9); - - LOG.info("My region is {}, ensemble : {}", repp.myRegion, ensemble); - - int ensembleSize = ensemble.size(); - for (int i = 0; i < ensembleSize; i++) { - DistributionSchedule.WriteSet writeSet = ds.getWriteSet(i); - DistributionSchedule.WriteSet readSet; - - if (isReadLAC) { - readSet = repp.reorderReadLACSequence( - ensemble, - getBookiesHealthInfo(), - writeSet.copy()); - } else { - readSet = repp.reorderReadSequence( - ensemble, - getBookiesHealthInfo(), - writeSet.copy()); - } - - assertEquals(writeSet, readSet); - } - } - - @Test - public void testReorderReadSequenceWithUnavailableOrReadOnlyBookies() throws Exception { - reorderReadSequenceWithUnavailableOrReadOnlyBookiesTest(false); - } - - @Test - public void testReorderReadLACSequenceWithUnavailableOrReadOnlyBookies() throws Exception { - reorderReadSequenceWithUnavailableOrReadOnlyBookiesTest(true); - } - - private Set getBookiesForRegion(List ensemble, String region) { - Set regionBookies = new HashSet(); - for (BookieId address : ensemble) { - String r = StaticDNSResolver.getRegion(repp.bookieAddressResolver - .resolve(address).getHostName()); - if (r.equals(region)) { - regionBookies.add(address); - } - } - return regionBookies; - } - - void appendBookieIndexByRegion(List ensemble, - DistributionSchedule.WriteSet writeSet, - String region, - List finalSet) { - for (int i = 0; i < writeSet.size(); i++) { - int bi = writeSet.get(i); - String r = StaticDNSResolver.getRegion(repp.bookieAddressResolver - .resolve(ensemble.get(bi)).getHostName()); - if (r.equals(region)) { - finalSet.add(bi); - } - } - } - - private void reorderReadSequenceWithUnavailableOrReadOnlyBookiesTest(boolean isReadLAC) throws Exception { - String myRegion = "region4"; - String unavailableRegion = "region1"; - String writeRegion = "region2"; - String readOnlyRegion = "region3"; - - prepareNetworkTopologyForReorderTests(myRegion); - - List ensemble = repp.newEnsemble(9, 9, 5, null, - new HashSet()).getResult(); - assertEquals(9, getNumCoveredRegionsInWriteQuorum(ensemble, 9)); - - DistributionSchedule ds = new RoundRobinDistributionSchedule(9, 9, 9); - - LOG.info("My region is {}, ensemble : {}", repp.myRegion, ensemble); - - Set readOnlyBookies = getBookiesForRegion(ensemble, readOnlyRegion); - Set writeBookies = getBookiesForRegion(ensemble, writeRegion); - - repp.onClusterChanged(writeBookies, readOnlyBookies); - - LOG.info("Writable Bookies {}, ReadOnly Bookies {}.", repp.knownBookies.keySet(), repp.readOnlyBookies); - - int ensembleSize = ensemble.size(); - for (int i = 0; i < ensembleSize; i++) { - DistributionSchedule.WriteSet writeSet = ds.getWriteSet(i); - DistributionSchedule.WriteSet readSet; - if (isReadLAC) { - readSet = repp.reorderReadLACSequence( - ensemble, getBookiesHealthInfo(), - writeSet.copy()); - } else { - readSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(), - writeSet.copy()); - } - - LOG.info("Reorder {} => {}.", writeSet, readSet); - - List expectedReadSet = new ArrayList(); - // writable bookies - appendBookieIndexByRegion(ensemble, writeSet, writeRegion, expectedReadSet); - // readonly bookies - appendBookieIndexByRegion(ensemble, writeSet, readOnlyRegion, expectedReadSet); - // unavailable bookies - appendBookieIndexByRegion(ensemble, writeSet, unavailableRegion, expectedReadSet); - assertEquals(expectedReadSet.size(), readSet.size()); - for (int j = 0; j < expectedReadSet.size(); j++) { - assertEquals(expectedReadSet.get(j).intValue(), readSet.get(j)); - } - } - } - - private int getNumRegionsInEnsemble(List ensemble) { - Set regions = new HashSet(); - for (BookieId addr: ensemble) { - regions.add(StaticDNSResolver.getRegion(repp.bookieAddressResolver.resolve(addr).getHostName())); - } - return regions.size(); - } - - private int getNumCoveredRegionsInWriteQuorum(List ensemble, int writeQuorumSize) - throws Exception { - int ensembleSize = ensemble.size(); - int numCoveredWriteQuorums = 0; - for (int i = 0; i < ensembleSize; i++) { - Set regions = new HashSet(); - for (int j = 0; j < writeQuorumSize; j++) { - int bookieIdx = (i + j) % ensembleSize; - BookieId addr = ensemble.get(bookieIdx); - regions.add(StaticDNSResolver.getRegion(repp.bookieAddressResolver.resolve(addr).getHostName())); - } - numCoveredWriteQuorums += (regions.size() > 1 ? 1 : 0); - } - return numCoveredWriteQuorums; - } - - @Test - public void testRecoveryOnNodeFailure() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - - // Update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region3/r3"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region3/r3"); - - // Update cluster - Set addrs = new HashSet<>(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - - repp.onClusterChanged(addrs, new HashSet<>()); - - Set bookiesLeftSet = new HashSet<>(); - bookiesLeftSet.add(addr1.toBookieId()); - repp.handleBookiesThatLeft(bookiesLeftSet); - - List currentEnsemble = new ArrayList<>(); - currentEnsemble.add(addr1.toBookieId()); - currentEnsemble.add(addr3.toBookieId()); - currentEnsemble.add(addr6.toBookieId()); - - EnsemblePlacementPolicy.PlacementResult placementResult = repp.replaceBookie(3, - 3, 2, null, - currentEnsemble, addr1.toBookieId(), new HashSet<>()); - - assertEquals(placementResult.getResult(), addr2.toBookieId()); - } - - @Test - public void testNodeWithFailures() throws Exception { - repp.uninitalize(); - updateMyRack("/r2/rack1"); - - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/r2/rack1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/r2/rack2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/r1/rack3"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/r2/rack3"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/r2/rack4"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/r1/rack4"); - ensemble.add(addr5.toBookieId()); - ensemble.add(addr6.toBookieId()); - ensemble.add(addr7.toBookieId()); - ensemble.add(addr8.toBookieId()); - - DistributionSchedule.WriteSet writeSet2 = writeSetFromValues(0, 1, 2, 3, 4, 5, 6, 7); - - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - HashMap bookieFailures = new HashMap(); - - bookieFailures.put(addr1.toBookieId(), 20L); - bookieFailures.put(addr2.toBookieId(), 22L); - bookieFailures.put(addr3.toBookieId(), 24L); - bookieFailures.put(addr4.toBookieId(), 25L); - - LOG.info("write set : {}", writeSet2); - DistributionSchedule.WriteSet reoderSet = repp.reorderReadSequence( - ensemble, getBookiesHealthInfo(bookieFailures, new HashMap<>()), writeSet2); - LOG.info("reorder set : {}", reoderSet); - assertEquals(ensemble.get(reoderSet.get(0)), addr6.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(1)), addr7.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(2)), addr5.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(3)), addr2.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(4)), addr3.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(5)), addr8.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(6)), addr1.toBookieId()); - assertEquals(ensemble.get(reoderSet.get(7)), addr4.toBookieId()); - } - - @Test - public void testNewEnsembleSetWithFiveRegions() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - - // Update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region3/r3"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region4/r4"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region5/r5"); - - // Update cluster - Set addrs = new HashSet<>(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - - repp.onClusterChanged(addrs, new HashSet<>()); - try { - List ensemble1 = repp.newEnsemble(3, 3, 2, - null, new HashSet<>()).getResult(); - assertEquals(ensemble1.size(), 3); - List ensemble2 = repp.newEnsemble(3, 3, 2, - null, new HashSet<>()).getResult(); - ensemble1.retainAll(ensemble2); - assert(ensemble1.size() >= 1); - - List ensemble3 = repp.newEnsemble(3, 3, 2, - null, new HashSet<>()).getResult(); - ensemble2.removeAll(ensemble3); - assert(ensemble2.size() >= 1); - } catch (BKNotEnoughBookiesException bnebe) { - fail("Should not get not enough bookies exception even there is only one rack."); - } - } - - @Test - public void testRegionsWithDiskWeight() throws Exception { - repp.uninitalize(); - repp = new RegionAwareEnsemblePlacementPolicy(); - conf.setProperty(REPP_ENABLE_VALIDATION, false); - conf.setDiskWeightBasedPlacementEnabled(true); - repp.initialize(conf, Optional.empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region2/r3"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region3/r11"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region4/r13"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region5/r23"); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - - repp.onClusterChanged(addrs, new HashSet()); - - List ensemble = repp.newEnsemble(3, 3, 2, null, - new HashSet<>()).getResult(); - - assertEquals(3, ensemble.size()); - } - - @Test - public void testNotifyRackChangeWithOldRegion() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.1.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.1.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.1.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.1.4", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/rack-1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/rack-1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/rack-1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/rack-1"); - - // Update cluster - Set addrs = Sets.newHashSet(addr1.toBookieId(), - addr2.toBookieId(), addr3.toBookieId(), addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet<>()); - - assertEquals(4, repp.knownBookies.size()); - assertEquals("/region1/rack-1", repp.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-1", repp.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", repp.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", repp.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - assertEquals(2, repp.perRegionPlacement.size()); - TopologyAwareEnsemblePlacementPolicy region1Placement = repp.perRegionPlacement.get("region1"); - assertEquals(2, region1Placement.knownBookies.keySet().size()); - assertEquals("/region1/rack-1", region1Placement.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-1", region1Placement.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - - TopologyAwareEnsemblePlacementPolicy region2Placement = repp.perRegionPlacement.get("region2"); - assertEquals(2, region2Placement.knownBookies.keySet().size()); - assertEquals("/region2/rack-1", region2Placement.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", region2Placement.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - assertEquals("region1", repp.address2Region.get(addr1.toBookieId())); - assertEquals("region1", repp.address2Region.get(addr2.toBookieId())); - assertEquals("region2", repp.address2Region.get(addr3.toBookieId())); - assertEquals("region2", repp.address2Region.get(addr4.toBookieId())); - - // Update the rack. - // change addr2 rack info. /region1/rack-1 -> /region1/rack-2. - // change addr4 rack info. /region2/rack-1 -> /region1/rack-2 - List bookieAddressList = new ArrayList<>(); - List rackList = new ArrayList<>(); - bookieAddressList.add(addr2); - rackList.add("/region1/rack-2"); - bookieAddressList.add(addr4); - rackList.add("/region1/rack-2"); - StaticDNSResolver.changeRack(bookieAddressList, rackList); - - assertEquals(4, repp.knownBookies.size()); - assertEquals("/region1/rack-1", repp.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-2", repp.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", repp.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-2", repp.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - assertEquals(2, repp.perRegionPlacement.size()); - region1Placement = repp.perRegionPlacement.get("region1"); - assertEquals(3, region1Placement.knownBookies.keySet().size()); - assertEquals("/region1/rack-1", region1Placement.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-2", region1Placement.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-2", region1Placement.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - region2Placement = repp.perRegionPlacement.get("region2"); - assertEquals(1, region2Placement.knownBookies.keySet().size()); - assertEquals("/region2/rack-1", region2Placement.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - - assertEquals("region1", repp.address2Region.get(addr1.toBookieId())); - assertEquals("region1", repp.address2Region.get(addr2.toBookieId())); - assertEquals("region2", repp.address2Region.get(addr3.toBookieId())); - assertEquals("region1", repp.address2Region.get(addr4.toBookieId())); - } - - @Test - public void testNotifyRackChangeWithNewRegion() throws Exception { - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.1.1", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.1.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.1.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.1.4", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/rack-1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region1/rack-1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/rack-1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/rack-1"); - - // Update cluster - Set addrs = Sets.newHashSet(addr1.toBookieId(), - addr2.toBookieId(), addr3.toBookieId(), addr4.toBookieId()); - repp.onClusterChanged(addrs, new HashSet<>()); - - assertEquals(4, repp.knownBookies.size()); - assertEquals("/region1/rack-1", repp.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-1", repp.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", repp.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", repp.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - assertEquals(2, repp.perRegionPlacement.size()); - TopologyAwareEnsemblePlacementPolicy region1Placement = repp.perRegionPlacement.get("region1"); - assertEquals(2, region1Placement.knownBookies.keySet().size()); - assertEquals("/region1/rack-1", region1Placement.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - assertEquals("/region1/rack-1", region1Placement.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - - TopologyAwareEnsemblePlacementPolicy region2Placement = repp.perRegionPlacement.get("region2"); - assertEquals(2, region2Placement.knownBookies.keySet().size()); - assertEquals("/region2/rack-1", region2Placement.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", region2Placement.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - assertEquals("region1", repp.address2Region.get(addr1.toBookieId())); - assertEquals("region1", repp.address2Region.get(addr2.toBookieId())); - assertEquals("region2", repp.address2Region.get(addr3.toBookieId())); - assertEquals("region2", repp.address2Region.get(addr4.toBookieId())); - - // Update the rack. - // change addr2 rack info. /region1/rack-1 -> /region3/rack-1. - // change addr4 rack info. /region2/rack-1 -> /region3/rack-1 - List bookieAddressList = new ArrayList<>(); - List rackList = new ArrayList<>(); - bookieAddressList.add(addr2); - rackList.add("/region3/rack-1"); - bookieAddressList.add(addr4); - rackList.add("/region3/rack-1"); - StaticDNSResolver.changeRack(bookieAddressList, rackList); - - assertEquals(4, repp.knownBookies.size()); - assertEquals("/region1/rack-1", repp.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - assertEquals("/region3/rack-1", repp.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - assertEquals("/region2/rack-1", repp.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - assertEquals("/region3/rack-1", repp.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - assertEquals(3, repp.perRegionPlacement.size()); - region1Placement = repp.perRegionPlacement.get("region1"); - assertEquals(1, region1Placement.knownBookies.keySet().size()); - assertEquals("/region1/rack-1", region1Placement.knownBookies.get(addr1.toBookieId()).getNetworkLocation()); - - region2Placement = repp.perRegionPlacement.get("region2"); - assertEquals(1, region2Placement.knownBookies.keySet().size()); - assertEquals("/region2/rack-1", region2Placement.knownBookies.get(addr3.toBookieId()).getNetworkLocation()); - - TopologyAwareEnsemblePlacementPolicy region3Placement = repp.perRegionPlacement.get("region3"); - assertEquals(2, region3Placement.knownBookies.keySet().size()); - assertEquals("/region3/rack-1", region3Placement.knownBookies.get(addr2.toBookieId()).getNetworkLocation()); - assertEquals("/region3/rack-1", region3Placement.knownBookies.get(addr4.toBookieId()).getNetworkLocation()); - - assertEquals("region1", repp.address2Region.get(addr1.toBookieId())); - assertEquals("region3", repp.address2Region.get(addr2.toBookieId())); - assertEquals("region2", repp.address2Region.get(addr3.toBookieId())); - assertEquals("region3", repp.address2Region.get(addr4.toBookieId())); - } - - - @Test - public void testNewEnsemblePickLocalRegionBookies() - throws Exception { - repp.uninitalize(); - BookieSocketAddress addr1 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr2 = new BookieSocketAddress("127.0.0.2", 3181); - BookieSocketAddress addr3 = new BookieSocketAddress("127.0.0.3", 3181); - BookieSocketAddress addr4 = new BookieSocketAddress("127.0.0.4", 3181); - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.5", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.9", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/region1/r1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region2/r2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/region3/r3"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/region4/r4"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/region5/r5"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/region1/r2"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/region1/r2"); - - - updateMyRack("/region1/r2"); - repp = new RegionAwareEnsemblePlacementPolicy(); - repp.initialize(conf, Optional.empty(), timer, - DISABLE_ALL, NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - repp.withDefaultRack(NetworkTopology.DEFAULT_REGION_AND_RACK); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - addrs.add(addr6.toBookieId()); - addrs.add(addr7.toBookieId()); - addrs.add(addr8.toBookieId()); - addrs.add(addr9.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - - int ensembleSize = 3; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - - Set excludeBookies = new HashSet<>(); - - int bookie1Count = 0; - int bookie8Count = 0; - int bookie9Count = 0; - for (int i = 0; i < 100; ++i) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - if (ensemble.contains(addr1.toBookieId())) { - bookie1Count++; - } - if (ensemble.contains(addr8.toBookieId())) { - bookie8Count++; - } - if (ensemble.contains(addr9.toBookieId())) { - bookie9Count++; - } - - if (!ensemble.contains(addr8.toBookieId()) && !ensemble.contains(addr9.toBookieId())) { - fail("Failed to select bookie located on the same region and rack with bookie client"); - } - if (ensemble.contains(addr2.toBookieId()) && ensemble.contains(addr3.toBookieId())) { - fail("addr2 and addr3 is same rack."); - } - } - LOG.info("Bookie1 Count: {}, Bookie8 Count: {}, Bookie9 Count: {}", bookie1Count, bookie8Count, bookie9Count); - - //shutdown all the bookies located in the same region and rack with local node - // to test new ensemble should contain addr1 - addrs.remove(addr8.toBookieId()); - addrs.remove(addr9.toBookieId()); - repp.onClusterChanged(addrs, new HashSet()); - bookie1Count = 0; - bookie8Count = 0; - bookie9Count = 0; - for (int i = 0; i < 100; ++i) { - try { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = - repp.newEnsemble(ensembleSize, writeQuorumSize, - ackQuorumSize, null, excludeBookies); - List ensemble = ensembleResponse.getResult(); - if (ensemble.contains(addr1.toBookieId())) { - bookie1Count++; - } - if (ensemble.contains(addr8.toBookieId())) { - bookie8Count++; - } - if (ensemble.contains(addr9.toBookieId())) { - bookie9Count++; - } - if (!ensemble.contains(addr1.toBookieId())) { - fail("Failed to select bookie located on the same region with bookie client"); - } - if (ensemble.contains(addr8.toBookieId()) || ensemble.contains(addr9.toBookieId())) { - fail("Selected the shutdown bookies"); - } - } catch (BKNotEnoughBookiesException e) { - fail("Failed to select the ensemble."); - } - } - LOG.info("Bookie1 Count: {}, Bookie8 Count: {}, Bookie9 Count: {}", bookie1Count, bookie8Count, bookie9Count); - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java deleted file mode 100644 index 1570599f628..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Lists; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test reading an entry from replicas in sequence way. - */ -public class TestSequenceRead extends BookKeeperClusterTestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestSequenceRead.class); - - public TestSequenceRead() { - super(5); - } - - private long createLedgerWithDuplicatedBookies() throws Exception { - long ledgerId = 12345L; - // introduce duplicated bookies in an ensemble. - LedgerMetadataBuilder builder = LedgerMetadataBuilder.create() - .withId(ledgerId).withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(getBookie(0), getBookie(0), getBookie(0))); - ClientUtil.setupLedger(bkc.getLedgerManager(), ledgerId, builder); - - logger.info("Update ledger metadata with duplicated bookies for ledger {}.", ledgerId); - return ledgerId; - } - - @Test - public void testSequenceReadOnDuplicatedBookies() throws Exception { - final long ledgerId = createLedgerWithDuplicatedBookies(); - - // should be able to open the ledger even it has duplicated bookies - final LedgerHandle readLh = bkc.openLedger( - ledgerId, DigestType.fromApiDigestType(ClientUtil.DIGEST_TYPE), ClientUtil.PASSWD); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeBatchRead.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeBatchRead.java deleted file mode 100644 index 3bf5e2d5e44..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeBatchRead.java +++ /dev/null @@ -1,401 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.BookKeeperClientStats.CLIENT_SCOPE; -import static org.apache.bookkeeper.client.BookKeeperClientStats.SPECULATIVE_READ_COUNT; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.BitSet; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.LocalBookieEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This unit test tests ledger fencing. - * - */ -public class TestSpeculativeBatchRead extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestSpeculativeBatchRead.class); - - private final DigestType digestType; - byte[] passwd = "specPW".getBytes(); - - public TestSpeculativeBatchRead() { - super(10); - this.digestType = DigestType.CRC32; - } - - long getLedgerToRead(int ensemble, int quorum) throws Exception { - byte[] data = "Data for test".getBytes(); - LedgerHandle l = bkc.createLedger(ensemble, quorum, digestType, passwd); - for (int i = 0; i < 10; i++) { - l.addEntry(data); - } - l.close(); - - return l.getId(); - } - - @SuppressWarnings("deprecation") - BookKeeperTestClient createClient(int specTimeout) throws Exception { - ClientConfiguration conf = new ClientConfiguration() - .setSpeculativeReadTimeout(specTimeout) - .setReadTimeout(30000) - .setUseV2WireProtocol(true) - .setReorderReadSequenceEnabled(true) - .setEnsemblePlacementPolicySlowBookies(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - return new BookKeeperTestClient(conf, new TestStatsProvider()); - } - - class LatchCallback implements ReadCallback { - CountDownLatch l = new CountDownLatch(1); - boolean success = false; - long startMillis = System.currentTimeMillis(); - long endMillis = Long.MAX_VALUE; - - public void readComplete(int rc, - LedgerHandle lh, - Enumeration seq, - Object ctx) { - endMillis = System.currentTimeMillis(); - if (LOG.isDebugEnabled()) { - LOG.debug("Got response {} {}", rc, getDuration()); - } - success = rc == BKException.Code.OK; - l.countDown(); - } - - long getDuration() { - return endMillis - startMillis; - } - - void expectSuccess(int milliseconds) throws Exception { - boolean await = l.await(milliseconds, TimeUnit.MILLISECONDS); - System.out.println(await); - } - - void expectFail(int milliseconds) throws Exception { - assertTrue(l.await(milliseconds, TimeUnit.MILLISECONDS)); - assertFalse(success); - } - - void expectTimeout(int milliseconds) throws Exception { - assertFalse(l.await(milliseconds, TimeUnit.MILLISECONDS)); - } - } - - /** - * Test basic speculative functionality. - * - Create 2 clients with read timeout disabled, one with spec - * read enabled, the other not. - * - create ledger - * - sleep second bookie in ensemble - * - read first entry, both should find on first bookie. - * - read second bookie, spec client should find on bookie three, - * non spec client should hang. - */ - @Test - public void testSpeculativeRead() throws Exception { - long id = getLedgerToRead(3, 2); - BookKeeperTestClient bknospec = createClient(0); // disabled - BookKeeperTestClient bkspec = createClient(2000); - - LedgerHandle lnospec = bknospec.openLedger(id, digestType, passwd); - LedgerHandle lspec = bkspec.openLedger(id, digestType, passwd); - - // sleep second bookie - CountDownLatch sleepLatch = new CountDownLatch(1); - BookieId second = lnospec.getLedgerMetadata().getAllEnsembles().get(0L).get(1); - sleepBookie(second, sleepLatch); - - try { - // read first entry, both go to first bookie, should be fine - LatchCallback nospeccb = new LatchCallback(); - LatchCallback speccb = new LatchCallback(); - lnospec.asyncBatchReadEntries(0, 1, 1024, nospeccb, null); - lspec.asyncBatchReadEntries(0, 1, 1024, speccb, null); - nospeccb.expectSuccess(2000); - speccb.expectSuccess(2000); - - // read second entry, both look for second book, spec read client - // tries third bookie, nonspec client hangs as read timeout is very long. - nospeccb = new LatchCallback(); - speccb = new LatchCallback(); - lnospec.asyncReadEntries(1, 1, nospeccb, null); - lspec.asyncReadEntries(1, 1, speccb, null); - speccb.expectSuccess(4000); - nospeccb.expectTimeout(4000); - // Check that the second bookie is registered as slow at entryId 1 - RackawareEnsemblePlacementPolicy rep = (RackawareEnsemblePlacementPolicy) bkspec.getPlacementPolicy(); - assertTrue(rep.slowBookies.asMap().size() == 1); - - assertTrue( - "Stats should not reflect speculative reads if disabled", - bknospec.getTestStatsProvider() - .getCounter(CLIENT_SCOPE + "." + SPECULATIVE_READ_COUNT).get() == 0); - assertTrue( - "Stats should reflect speculative reads", - bkspec.getTestStatsProvider() - .getCounter(CLIENT_SCOPE + "." + SPECULATIVE_READ_COUNT).get() > 0); - } finally { - sleepLatch.countDown(); - lspec.close(); - lnospec.close(); - bkspec.close(); - bknospec.close(); - } - } - - /** - * Test that if more than one replica is down, we can still read, as long as the quorum - * size is larger than the number of down replicas. - */ - @Test - public void testSpeculativeReadMultipleReplicasDown() throws Exception { - long id = getLedgerToRead(5, 5); - int timeout = 5000; - BookKeeper bkspec = createClient(timeout); - - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - - // sleep bookie 1, 2 & 4 - CountDownLatch sleepLatch = new CountDownLatch(1); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(1), sleepLatch); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(2), sleepLatch); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(4), sleepLatch); - - try { - // read first entry, should complete faster than timeout - // as bookie 0 has the entry - LatchCallback latch0 = new LatchCallback(); - l.asyncBatchReadEntries(0, 1, 1024, latch0, null); - latch0.expectSuccess(timeout / 2); - - // second should have to hit two timeouts (bookie 1 & 2) - // bookie 3 has the entry - LatchCallback latch1 = new LatchCallback(); - l.asyncBatchReadEntries(1, 1, 1024, latch1, null); - latch1.expectTimeout(timeout); - latch1.expectSuccess(timeout * 2); - LOG.info("Timeout {} latch1 duration {}", timeout, latch1.getDuration()); - assertTrue("should have taken longer than two timeouts, but less than 3", - latch1.getDuration() >= timeout * 2 - && latch1.getDuration() < timeout * 3); - - // bookies 1 & 2 should be registered as slow bookies because of speculative reads - Set expectedSlowBookies = new HashSet<>(); - expectedSlowBookies.add(l.getLedgerMetadata().getAllEnsembles().get(0L).get(1)); - expectedSlowBookies.add(l.getLedgerMetadata().getAllEnsembles().get(0L).get(2)); - assertEquals(((RackawareEnsemblePlacementPolicy) bkspec.getPlacementPolicy()).slowBookies.asMap().keySet(), - expectedSlowBookies); - - // third should not hit timeouts since bookies 1 & 2 are registered as slow - // bookie 3 has the entry - LatchCallback latch2 = new LatchCallback(); - l.asyncBatchReadEntries(2, 1, 1024, latch2, null); - latch2.expectSuccess(timeout); - - // fourth should have no timeout - // bookie 3 has the entry - LatchCallback latch3 = new LatchCallback(); - l.asyncBatchReadEntries(3, 1, 1024, latch3, null); - latch3.expectSuccess(timeout / 2); - - // fifth should hit one timeout, (bookie 4) - // bookie 0 has the entry - LatchCallback latch4 = new LatchCallback(); - l.asyncBatchReadEntries(4, 1, 1024, latch4, null); - latch4.expectTimeout(timeout / 2); - latch4.expectSuccess(timeout); - LOG.info("Timeout {} latch4 duration {}", timeout, latch4.getDuration()); - assertTrue("should have taken longer than one timeout, but less than 2", - latch4.getDuration() >= timeout - && latch4.getDuration() < timeout * 2); - } finally { - sleepLatch.countDown(); - l.close(); - bkspec.close(); - } - } - - /** - * Test that if after a speculative read is kicked off, the original read completes - * nothing bad happens. - */ - @Test - public void testSpeculativeReadFirstReadCompleteIsOk() throws Exception { - long id = getLedgerToRead(2, 2); - int timeout = 1000; - BookKeeper bkspec = createClient(timeout); - - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - - // sleep bookies - CountDownLatch sleepLatch0 = new CountDownLatch(1); - CountDownLatch sleepLatch1 = new CountDownLatch(1); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(0), sleepLatch0); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(1), sleepLatch1); - - try { - // read goes to first bookie, spec read timeout occurs, - // goes to second - LatchCallback latch0 = new LatchCallback(); - l.asyncBatchReadEntries(0, 1, 1024, latch0, null); - latch0.expectTimeout(timeout); - - // wake up first bookie - sleepLatch0.countDown(); - latch0.expectSuccess(timeout / 2); - - sleepLatch1.countDown(); - - // check we can read next entry without issue - LatchCallback latch1 = new LatchCallback(); - l.asyncBatchReadEntries(1, 1, 1024, latch1, null); - latch1.expectSuccess(timeout / 2); - } finally { - sleepLatch0.countDown(); - sleepLatch1.countDown(); - l.close(); - bkspec.close(); - } - } - - /** - * Unit test to check if the scheduled speculative task gets cancelled - * on successful read. - */ - @Test - public void testSpeculativeReadScheduledTaskCancel() throws Exception { - long id = getLedgerToRead(3, 2); - int timeout = 1000; - BookKeeper bkspec = createClient(timeout); - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - BatchedReadOp op = null; - try { - op = new BatchedReadOp(l, bkspec.getClientCtx(), 0, 5, 5120, false); - op.initiate(); - op.future().get(); - } finally { - assertNull("Speculative Read tasks must be null", op.getSpeculativeTask()); - } - } - - /** - * Unit test for the speculative read scheduling method. - */ - @Test - public void testSpeculativeReadScheduling() throws Exception { - long id = getLedgerToRead(3, 2); - int timeout = 1000; - BookKeeper bkspec = createClient(timeout); - - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - - List ensemble = l.getLedgerMetadata().getAllEnsembles().get(0L); - BitSet allHosts = new BitSet(ensemble.size()); - for (int i = 0; i < ensemble.size(); i++) { - allHosts.set(i, true); - } - BitSet noHost = new BitSet(ensemble.size()); - BitSet secondHostOnly = new BitSet(ensemble.size()); - secondHostOnly.set(1, true); - BatchedReadOp.LedgerEntryRequest req0 = null, req2 = null, req4 = null; - try { - BatchedReadOp op = new BatchedReadOp(l, bkspec.getClientCtx(), 0, 5, 5120, false); - // if we've already heard from all hosts, - // we only send the initial read - req0 = op.new SequenceReadRequest(ensemble, l.getId(), 0, 1, 1024); - assertTrue("Should have sent to first", - req0.maybeSendSpeculativeRead(allHosts).equals(ensemble.get(0))); - assertNull("Should not have sent another", - req0.maybeSendSpeculativeRead(allHosts)); - - // if we have heard from some hosts, but not one we have sent to - // send again - req2 = op.new SequenceReadRequest(ensemble, l.getId(), 2, 1, 1024); - assertTrue("Should have sent to third", - req2.maybeSendSpeculativeRead(noHost).equals(ensemble.get(2))); - assertTrue("Should have sent to first", - req2.maybeSendSpeculativeRead(secondHostOnly).equals(ensemble.get(0))); - - // if we have heard from some hosts, which includes one we sent to - // do not read again - req4 = op.new SequenceReadRequest(ensemble, l.getId(), 4, 1, 1024); - assertTrue("Should have sent to second", - req4.maybeSendSpeculativeRead(noHost).equals(ensemble.get(1))); - assertNull("Should not have sent another", - req4.maybeSendSpeculativeRead(secondHostOnly)); - } finally { - for (BatchedReadOp.LedgerEntryRequest req - : new BatchedReadOp.LedgerEntryRequest[] { req0, req2, req4 }) { - if (req != null) { - int i = 0; - while (!req.isComplete()) { - if (i++ > 10) { - break; // wait for up to 10 seconds - } - Thread.sleep(1000); - } - assertTrue("Request should be done", req.isComplete()); - } - } - - l.close(); - bkspec.close(); - } - } - - @Test - public void testSequenceReadLocalEnsemble() throws Exception { - ClientConfiguration conf = new ClientConfiguration() - .setSpeculativeReadTimeout(1000) - .setEnsemblePlacementPolicy(LocalBookieEnsemblePlacementPolicy.class) - .setReorderReadSequenceEnabled(true) - .setEnsemblePlacementPolicySlowBookies(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkspec = new BookKeeperTestClient(conf, new TestStatsProvider()); - LedgerHandle l = bkspec.createLedger(1, 1, digestType, passwd); - List ensemble = l.getLedgerMetadata().getAllEnsembles().get(0L); - BatchedReadOp op = new BatchedReadOp(l, bkspec.getClientCtx(), 0, 5, 5120, false); - BatchedReadOp.LedgerEntryRequest req0 = op.new SequenceReadRequest(ensemble, l.getId(), 0, 1, 1024); - assertNotNull(req0.writeSet); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeRead.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeRead.java deleted file mode 100644 index 177f85a00ba..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeRead.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.BookKeeperClientStats.CLIENT_SCOPE; -import static org.apache.bookkeeper.client.BookKeeperClientStats.SPECULATIVE_READ_COUNT; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.BitSet; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.LocalBookieEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This unit test tests ledger fencing. - * - */ -public class TestSpeculativeRead extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestSpeculativeRead.class); - - private final DigestType digestType; - byte[] passwd = "specPW".getBytes(); - - public TestSpeculativeRead() { - super(10); - this.digestType = DigestType.CRC32; - } - - long getLedgerToRead(int ensemble, int quorum) throws Exception { - byte[] data = "Data for test".getBytes(); - LedgerHandle l = bkc.createLedger(ensemble, quorum, digestType, passwd); - for (int i = 0; i < 10; i++) { - l.addEntry(data); - } - l.close(); - - return l.getId(); - } - - @SuppressWarnings("deprecation") - BookKeeperTestClient createClient(int specTimeout) throws Exception { - ClientConfiguration conf = new ClientConfiguration() - .setSpeculativeReadTimeout(specTimeout) - .setReadTimeout(30000) - .setReorderReadSequenceEnabled(true) - .setEnsemblePlacementPolicySlowBookies(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - return new BookKeeperTestClient(conf, new TestStatsProvider()); - } - - class LatchCallback implements ReadCallback { - CountDownLatch l = new CountDownLatch(1); - boolean success = false; - long startMillis = System.currentTimeMillis(); - long endMillis = Long.MAX_VALUE; - - public void readComplete(int rc, - LedgerHandle lh, - Enumeration seq, - Object ctx) { - endMillis = System.currentTimeMillis(); - if (LOG.isDebugEnabled()) { - LOG.debug("Got response {} {}", rc, getDuration()); - } - success = rc == BKException.Code.OK; - l.countDown(); - } - - long getDuration() { - return endMillis - startMillis; - } - - void expectSuccess(int milliseconds) throws Exception { - assertTrue(l.await(milliseconds, TimeUnit.MILLISECONDS)); - assertTrue(success); - } - - void expectFail(int milliseconds) throws Exception { - assertTrue(l.await(milliseconds, TimeUnit.MILLISECONDS)); - assertFalse(success); - } - - void expectTimeout(int milliseconds) throws Exception { - assertFalse(l.await(milliseconds, TimeUnit.MILLISECONDS)); - } - } - - /** - * Test basic speculative functionality. - * - Create 2 clients with read timeout disabled, one with spec - * read enabled, the other not. - * - create ledger - * - sleep second bookie in ensemble - * - read first entry, both should find on first bookie. - * - read second bookie, spec client should find on bookie three, - * non spec client should hang. - */ - @Test - public void testSpeculativeRead() throws Exception { - long id = getLedgerToRead(3, 2); - BookKeeperTestClient bknospec = createClient(0); // disabled - BookKeeperTestClient bkspec = createClient(2000); - - LedgerHandle lnospec = bknospec.openLedger(id, digestType, passwd); - LedgerHandle lspec = bkspec.openLedger(id, digestType, passwd); - - // sleep second bookie - CountDownLatch sleepLatch = new CountDownLatch(1); - BookieId second = lnospec.getLedgerMetadata().getAllEnsembles().get(0L).get(1); - sleepBookie(second, sleepLatch); - - try { - // read first entry, both go to first bookie, should be fine - LatchCallback nospeccb = new LatchCallback(); - LatchCallback speccb = new LatchCallback(); - lnospec.asyncReadEntries(0, 0, nospeccb, null); - lspec.asyncReadEntries(0, 0, speccb, null); - nospeccb.expectSuccess(2000); - speccb.expectSuccess(2000); - - // read second entry, both look for second book, spec read client - // tries third bookie, nonspec client hangs as read timeout is very long. - nospeccb = new LatchCallback(); - speccb = new LatchCallback(); - lnospec.asyncReadEntries(1, 1, nospeccb, null); - lspec.asyncReadEntries(1, 1, speccb, null); - speccb.expectSuccess(4000); - nospeccb.expectTimeout(4000); - // Check that the second bookie is registered as slow at entryId 1 - RackawareEnsemblePlacementPolicy rep = (RackawareEnsemblePlacementPolicy) bkspec.getPlacementPolicy(); - assertTrue(rep.slowBookies.asMap().size() == 1); - - assertTrue( - "Stats should not reflect speculative reads if disabled", - bknospec.getTestStatsProvider() - .getCounter(CLIENT_SCOPE + "." + SPECULATIVE_READ_COUNT).get() == 0); - assertTrue( - "Stats should reflect speculative reads", - bkspec.getTestStatsProvider() - .getCounter(CLIENT_SCOPE + "." + SPECULATIVE_READ_COUNT).get() > 0); - - } finally { - sleepLatch.countDown(); - lspec.close(); - lnospec.close(); - bkspec.close(); - bknospec.close(); - } - } - - /** - * Test that if more than one replica is down, we can still read, as long as the quorum - * size is larger than the number of down replicas. - */ - @Test - public void testSpeculativeReadMultipleReplicasDown() throws Exception { - long id = getLedgerToRead(5, 5); - int timeout = 5000; - BookKeeper bkspec = createClient(timeout); - - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - - // sleep bookie 1, 2 & 4 - CountDownLatch sleepLatch = new CountDownLatch(1); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(1), sleepLatch); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(2), sleepLatch); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(4), sleepLatch); - - try { - // read first entry, should complete faster than timeout - // as bookie 0 has the entry - LatchCallback latch0 = new LatchCallback(); - l.asyncReadEntries(0, 0, latch0, null); - latch0.expectSuccess(timeout / 2); - - // second should have to hit two timeouts (bookie 1 & 2) - // bookie 3 has the entry - LatchCallback latch1 = new LatchCallback(); - l.asyncReadEntries(1, 1, latch1, null); - latch1.expectTimeout(timeout); - latch1.expectSuccess(timeout * 2); - LOG.info("Timeout {} latch1 duration {}", timeout, latch1.getDuration()); - assertTrue("should have taken longer than two timeouts, but less than 3", - latch1.getDuration() >= timeout * 2 - && latch1.getDuration() < timeout * 3); - - // bookies 1 & 2 should be registered as slow bookies because of speculative reads - Set expectedSlowBookies = new HashSet<>(); - expectedSlowBookies.add(l.getLedgerMetadata().getAllEnsembles().get(0L).get(1)); - expectedSlowBookies.add(l.getLedgerMetadata().getAllEnsembles().get(0L).get(2)); - assertEquals(((RackawareEnsemblePlacementPolicy) bkspec.getPlacementPolicy()).slowBookies.asMap().keySet(), - expectedSlowBookies); - - // third should not hit timeouts since bookies 1 & 2 are registered as slow - // bookie 3 has the entry - LatchCallback latch2 = new LatchCallback(); - l.asyncReadEntries(2, 2, latch2, null); - latch2.expectSuccess(timeout); - - // fourth should have no timeout - // bookie 3 has the entry - LatchCallback latch3 = new LatchCallback(); - l.asyncReadEntries(3, 3, latch3, null); - latch3.expectSuccess(timeout / 2); - - // fifth should hit one timeout, (bookie 4) - // bookie 0 has the entry - LatchCallback latch4 = new LatchCallback(); - l.asyncReadEntries(4, 4, latch4, null); - latch4.expectTimeout(timeout / 2); - latch4.expectSuccess(timeout); - LOG.info("Timeout {} latch4 duration {}", timeout, latch4.getDuration()); - assertTrue("should have taken longer than one timeout, but less than 2", - latch4.getDuration() >= timeout - && latch4.getDuration() < timeout * 2); - - } finally { - sleepLatch.countDown(); - l.close(); - bkspec.close(); - } - } - - /** - * Test that if after a speculative read is kicked off, the original read completes - * nothing bad happens. - */ - @Test - public void testSpeculativeReadFirstReadCompleteIsOk() throws Exception { - long id = getLedgerToRead(2, 2); - int timeout = 1000; - BookKeeper bkspec = createClient(timeout); - - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - - // sleep bookies - CountDownLatch sleepLatch0 = new CountDownLatch(1); - CountDownLatch sleepLatch1 = new CountDownLatch(1); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(0), sleepLatch0); - sleepBookie(l.getLedgerMetadata().getAllEnsembles().get(0L).get(1), sleepLatch1); - - try { - // read goes to first bookie, spec read timeout occurs, - // goes to second - LatchCallback latch0 = new LatchCallback(); - l.asyncReadEntries(0, 0, latch0, null); - latch0.expectTimeout(timeout); - - // wake up first bookie - sleepLatch0.countDown(); - latch0.expectSuccess(timeout / 2); - - sleepLatch1.countDown(); - - // check we can read next entry without issue - LatchCallback latch1 = new LatchCallback(); - l.asyncReadEntries(1, 1, latch1, null); - latch1.expectSuccess(timeout / 2); - - } finally { - sleepLatch0.countDown(); - sleepLatch1.countDown(); - l.close(); - bkspec.close(); - } - } - - /** - * Unit test to check if the scheduled speculative task gets cancelled - * on successful read. - */ - @Test - public void testSpeculativeReadScheduledTaskCancel() throws Exception { - long id = getLedgerToRead(3, 2); - int timeout = 1000; - BookKeeper bkspec = createClient(timeout); - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - PendingReadOp op = null; - try { - op = new PendingReadOp(l, bkspec.getClientCtx(), 0, 5, false); - op.initiate(); - op.future().get(); - } finally { - assertNull("Speculative Read tasks must be null", op.getSpeculativeTask()); - } - } - - /** - * Unit test for the speculative read scheduling method. - */ - @Test - public void testSpeculativeReadScheduling() throws Exception { - long id = getLedgerToRead(3, 2); - int timeout = 1000; - BookKeeper bkspec = createClient(timeout); - - LedgerHandle l = bkspec.openLedger(id, digestType, passwd); - - List ensemble = l.getLedgerMetadata().getAllEnsembles().get(0L); - BitSet allHosts = new BitSet(ensemble.size()); - for (int i = 0; i < ensemble.size(); i++) { - allHosts.set(i, true); - } - BitSet noHost = new BitSet(ensemble.size()); - BitSet secondHostOnly = new BitSet(ensemble.size()); - secondHostOnly.set(1, true); - PendingReadOp.LedgerEntryRequest req0 = null, req2 = null, req4 = null; - try { - PendingReadOp op = new PendingReadOp(l, bkspec.getClientCtx(), 0, 5, false); - // if we've already heard from all hosts, - // we only send the initial read - req0 = op.new SequenceReadRequest(ensemble, l.getId(), 0); - assertTrue("Should have sent to first", - req0.maybeSendSpeculativeRead(allHosts).equals(ensemble.get(0))); - assertNull("Should not have sent another", - req0.maybeSendSpeculativeRead(allHosts)); - - // if we have heard from some hosts, but not one we have sent to - // send again - req2 = op.new SequenceReadRequest(ensemble, l.getId(), 2); - assertTrue("Should have sent to third", - req2.maybeSendSpeculativeRead(noHost).equals(ensemble.get(2))); - assertTrue("Should have sent to first", - req2.maybeSendSpeculativeRead(secondHostOnly).equals(ensemble.get(0))); - - // if we have heard from some hosts, which includes one we sent to - // do not read again - req4 = op.new SequenceReadRequest(ensemble, l.getId(), 4); - assertTrue("Should have sent to second", - req4.maybeSendSpeculativeRead(noHost).equals(ensemble.get(1))); - assertNull("Should not have sent another", - req4.maybeSendSpeculativeRead(secondHostOnly)); - } finally { - for (PendingReadOp.LedgerEntryRequest req - : new PendingReadOp.LedgerEntryRequest[] { req0, req2, req4 }) { - if (req != null) { - int i = 0; - while (!req.isComplete()) { - if (i++ > 10) { - break; // wait for up to 10 seconds - } - Thread.sleep(1000); - } - assertTrue("Request should be done", req.isComplete()); - } - } - - l.close(); - bkspec.close(); - } - } - - @Test - public void testSequenceReadLocalEnsemble() throws Exception { - ClientConfiguration conf = new ClientConfiguration() - .setSpeculativeReadTimeout(1000) - .setEnsemblePlacementPolicy(LocalBookieEnsemblePlacementPolicy.class) - .setReorderReadSequenceEnabled(true) - .setEnsemblePlacementPolicySlowBookies(true) - .setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper bkspec = new BookKeeperTestClient(conf, new TestStatsProvider()); - LedgerHandle l = bkspec.createLedger(1, 1, digestType, passwd); - List ensemble = l.getLedgerMetadata().getAllEnsembles().get(0L); - PendingReadOp op = new PendingReadOp(l, bkspec.getClientCtx(), 0, 5, false); - PendingReadOp.LedgerEntryRequest req0 = op.new SequenceReadRequest(ensemble, l.getId(), 0); - assertNotNull(req0.writeSet); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestTryReadLastConfirmed.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestTryReadLastConfirmed.java deleted file mode 100644 index 18d070ebada..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestTryReadLastConfirmed.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test try read last confirmed. - */ -public class TestTryReadLastConfirmed extends BookKeeperClusterTestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestTryReadLastConfirmed.class); - - final DigestType digestType; - - public TestTryReadLastConfirmed() { - super(6); - this.digestType = DigestType.CRC32; - } - - @Test - public void testTryReadLACWhenAllBookiesUp() throws Exception { - final int numEntries = 3; - - final LedgerHandle lh = bkc.createLedger(3, 3, 1, digestType, "".getBytes()); - LedgerHandle readLh = bkc.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - // add entries - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + i).getBytes()); - } - final AtomicBoolean success = new AtomicBoolean(false); - final AtomicInteger numCallbacks = new AtomicInteger(0); - final CountDownLatch latch1 = new CountDownLatch(1); - readLh.asyncTryReadLastConfirmed(new AsyncCallback.ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc) { - success.set(true); - } else { - success.set(false); - } - latch1.countDown(); - } - }, null); - latch1.await(); - TimeUnit.SECONDS.sleep(2); - assertTrue(success.get()); - assertTrue(numCallbacks.get() == 1); - assertEquals(numEntries - 2, readLh.getLastAddConfirmed()); - // try read last confirmed again - success.set(false); - numCallbacks.set(0); - final CountDownLatch latch2 = new CountDownLatch(1); - readLh.asyncTryReadLastConfirmed(new AsyncCallback.ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc && lastConfirmed == (numEntries - 2)) { - success.set(true); - } else { - success.set(false); - } - latch2.countDown(); - } - }, null); - latch2.await(); - TimeUnit.SECONDS.sleep(2); - assertTrue(success.get()); - assertTrue(numCallbacks.get() == 1); - assertEquals(numEntries - 2, readLh.getLastAddConfirmed()); - - lh.close(); - readLh.close(); - } - - @Test - public void testTryReadLaCWhenSomeBookiesDown() throws Exception { - final int numEntries = 3; - final int ensembleSize = 3; - final LedgerHandle lh = bkc.createLedger(ensembleSize, 1, 1, digestType, "".getBytes()); - LedgerHandle readLh = bkc.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - // add entries - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + i).getBytes()); - } - for (int i = 0; i < numEntries; i++) { - ServerConfiguration[] confs = new ServerConfiguration[ensembleSize - 1]; - for (int j = 0; j < ensembleSize - 1; j++) { - int idx = (i + 1 + j) % ensembleSize; - confs[j] = killBookie(lh.getCurrentEnsemble().get(idx)); - } - - final AtomicBoolean success = new AtomicBoolean(false); - final AtomicInteger numCallbacks = new AtomicInteger(0); - final CountDownLatch latch = new CountDownLatch(1); - final int entryId = i; - readLh.asyncTryReadLastConfirmed(new AsyncCallback.ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc) { - success.set(lastConfirmed == (entryId - 1)); - } else { - success.set(false); - } - latch.countDown(); - } - }, null); - latch.await(); - assertTrue(success.get()); - assertTrue(numCallbacks.get() == 1); - - // start the bookies - for (ServerConfiguration conf : confs) { - startAndAddBookie(conf); - } - } - lh.close(); - readLh.close(); - } - - @Test - public void testTryReadLACWhenAllBookiesDown() throws Exception { - final int numEntries = 2; - final int ensembleSize = 3; - final LedgerHandle lh = bkc.createLedger(ensembleSize, 1, 1, digestType, "".getBytes()); - LedgerHandle readLh = bkc.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - assertEquals(LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - // add entries - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + i).getBytes()); - } - for (int i = 0; i < ensembleSize; i++) { - killBookie(lh.getCurrentEnsemble().get(i)); - } - final AtomicBoolean success = new AtomicBoolean(false); - final AtomicInteger numCallbacks = new AtomicInteger(0); - final CountDownLatch latch = new CountDownLatch(1); - readLh.asyncTryReadLastConfirmed(new AsyncCallback.ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - logger.info("ReadLastConfirmedComplete : rc = {}, lac = {}.", rc, lastConfirmed); - numCallbacks.incrementAndGet(); - if (BKException.Code.OK == rc) { - success.set(lastConfirmed == LedgerHandle.INVALID_ENTRY_ID); - } else { - success.set(false); - } - latch.countDown(); - } - }, null); - latch.await(); - TimeUnit.SECONDS.sleep(2); - assertFalse(success.get()); - assertTrue(numCallbacks.get() == 1); - - lh.close(); - readLh.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWatchEnsembleChange.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWatchEnsembleChange.java deleted file mode 100644 index 18c783327c3..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWatchEnsembleChange.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.UncheckedExecutionException; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import lombok.Cleanup; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerIdGenerator; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LongHierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.LedgerMetadataListener; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test an EnsembleChange watcher. - */ -@RunWith(Parameterized.class) -public class TestWatchEnsembleChange extends BookKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestWatchEnsembleChange.class); - - final DigestType digestType; - final Class lmFactoryCls; - - public TestWatchEnsembleChange(Class lmFactoryCls) { - super(7); - this.digestType = DigestType.CRC32; - this.lmFactoryCls = lmFactoryCls; - baseClientConf.setLedgerManagerFactoryClass(lmFactoryCls); - baseConf.setLedgerManagerFactoryClass(lmFactoryCls); - } - - @SuppressWarnings("deprecation") - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { - { org.apache.bookkeeper.meta.FlatLedgerManagerFactory.class }, - { HierarchicalLedgerManagerFactory.class }, - { LongHierarchicalLedgerManagerFactory.class }, - { org.apache.bookkeeper.meta.MSLedgerManagerFactory.class }, - }); - } - - @Test - public void testWatchEnsembleChange() throws Exception { - int numEntries = 10; - LedgerHandle lh = bkc.createLedger(3, 3, 3, digestType, "".getBytes()); - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + i).getBytes()); - LOG.info("Added entry {}.", i); - } - LedgerHandle readLh = bkc.openLedgerNoRecovery(lh.getId(), digestType, "".getBytes()); - long lastLAC = readLh.getLastAddConfirmed(); - assertEquals(numEntries - 2, lastLAC); - List ensemble = - lh.getCurrentEnsemble(); - for (BookieId addr : ensemble) { - killBookie(addr); - } - // write another batch of entries, which will trigger ensemble change - for (int i = 0; i < numEntries; i++) { - lh.addEntry(("data" + (numEntries + i)).getBytes()); - LOG.info("Added entry {}.", (numEntries + i)); - } - TimeUnit.SECONDS.sleep(5); - readLh.readLastConfirmed(); - assertEquals(2 * numEntries - 2, readLh.getLastAddConfirmed()); - readLh.close(); - lh.close(); - } - - @Test - public void testWatchMetadataRemoval() throws Exception { - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - runFunctionWithLedgerManagerFactory(baseConf, factory -> { - try { - testWatchMetadataRemoval(factory); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - return null; - }); - } - - private void testWatchMetadataRemoval(LedgerManagerFactory factory) throws Exception { - @Cleanup final LedgerManager manager = factory.newLedgerManager(); - @Cleanup LedgerIdGenerator idGenerator = factory.newLedgerIdGenerator(); - - final ByteBuffer bbLedgerId = ByteBuffer.allocate(8); - final CountDownLatch createLatch = new CountDownLatch(1); - final CountDownLatch removeLatch = new CountDownLatch(1); - - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.4", 1234).toBookieId()); - idGenerator.generateLedgerId(new GenericCallback() { - @Override - public void operationComplete(int rc, final Long lid) { - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(lid) - .withDigestType(digestType.toApiDigestType()).withPassword(new byte[0]) - .withEnsembleSize(4).withWriteQuorumSize(2) - .withAckQuorumSize(2) - .newEnsembleEntry(0L, ensemble).build(); - manager.createLedgerMetadata(lid, metadata) - .whenComplete((result, exception) -> { - bbLedgerId.putLong(lid); - bbLedgerId.flip(); - createLatch.countDown(); - }); - } - }); - - assertTrue(createLatch.await(2000, TimeUnit.MILLISECONDS)); - final long createdLid = bbLedgerId.getLong(); - - manager.registerLedgerMetadataListener(createdLid, - new LedgerMetadataListener() { - - @Override - public void onChanged(long ledgerId, Versioned metadata) { - assertEquals(ledgerId, createdLid); - assertEquals(metadata, null); - removeLatch.countDown(); - } - }); - - manager.removeLedgerMetadata(createdLid, Version.ANY).get(2, TimeUnit.SECONDS); - assertTrue(removeLatch.await(2, TimeUnit.SECONDS)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWeightedRandomSelection.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWeightedRandomSelection.java deleted file mode 100644 index 1fe2d656e11..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWeightedRandomSelection.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.apache.bookkeeper.client.WeightedRandomSelection.WeightedObject; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.junit.After; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test weighted random selection methods. - */ -@RunWith(Parameterized.class) -public class TestWeightedRandomSelection { - - static final Logger LOG = LoggerFactory.getLogger(TestWeightedRandomSelection.class); - - static class TestObj implements WeightedObject { - long val; - - TestObj(long value) { - this.val = value; - } - - @Override - public long getWeight() { - return val; - } - } - - Class weightedRandomSelectionClass; - WeightedRandomSelection wRS; - Configuration conf = new CompositeConfiguration(); - int multiplier = 3; - - @Parameters - public static Collection weightedRandomSelectionClass() { - return Arrays.asList( - new Object[][] { { WeightedRandomSelectionImpl.class }, { DynamicWeightedRandomSelectionImpl.class } }); - } - - public TestWeightedRandomSelection(Class weightedRandomSelectionClass) { - this.weightedRandomSelectionClass = weightedRandomSelectionClass; - } - - @Before - public void setUp() throws Exception { - if (weightedRandomSelectionClass.equals(WeightedRandomSelectionImpl.class)) { - wRS = new WeightedRandomSelectionImpl(); - } else { - wRS = new DynamicWeightedRandomSelectionImpl(); - } - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testSelectionWithEqualWeights() throws Exception { - Map map = new HashMap(); - - Long val = 100L; - int numKeys = 50, totalTries = 1000000; - Map randomSelection = new HashMap(); - for (Integer i = 0; i < numKeys; i++) { - map.put(i.toString(), new TestObj(val)); - randomSelection.put(i.toString(), 0); - } - - wRS.updateMap(map); - for (int i = 0; i < totalTries; i++) { - String key = wRS.getNextRandom(); - randomSelection.put(key, randomSelection.get(key) + 1); - } - - // there should be uniform distribution - double expectedPct = ((double) 1 / (double) numKeys) * 100; - for (Map.Entry e : randomSelection.entrySet()) { - double actualPct = ((double) e.getValue() / (double) totalTries) * 100; - double delta = (Math.abs(expectedPct - actualPct) / expectedPct) * 100; - System.out.println("Key:" + e.getKey() + " Value:" + e.getValue() + " Expected: " + expectedPct - + " Actual: " + actualPct + " delta: " + delta); - // should be within 5% of expected - assertTrue("Not doing uniform selection when weights are equal", delta < 5); - } - } - - @Test - public void testSelectionWithAllZeroWeights() throws Exception { - Map map = new HashMap(); - - int numKeys = 50, totalTries = 1000000; - Map randomSelection = new HashMap(); - for (Integer i = 0; i < numKeys; i++) { - map.put(i.toString(), new TestObj(0L)); - randomSelection.put(i.toString(), 0); - } - - wRS.updateMap(map); - for (int i = 0; i < totalTries; i++) { - String key = wRS.getNextRandom(); - randomSelection.put(key, randomSelection.get(key) + 1); - } - - // when all the values are zeros, there should be uniform distribution - double expectedPct = ((double) 1 / (double) numKeys) * 100; - for (Map.Entry e : randomSelection.entrySet()) { - double actualPct = ((double) e.getValue() / (double) totalTries) * 100; - double delta = (Math.abs(expectedPct - actualPct) / expectedPct) * 100; - System.out.println("Key:" + e.getKey() + " Value:" + e.getValue() + " Expected: " + expectedPct - + " Actual: " + actualPct); - // should be within 5% of expected - assertTrue("Not doing uniform selection when weights are equal", delta < 5); - } - } - - void verifyResult(Map map, Map randomSelection, int multiplier, - long minWeight, long medianWeight, long totalWeight, int totalTries) { - List values = new ArrayList(randomSelection.values()); - Collections.sort(values); - double medianObserved, medianObservedWeight, medianExpectedWeight; - int mid = values.size() / 2; - if ((values.size() % 2) == 1) { - medianObserved = values.get(mid); - } else { - medianObserved = (double) (values.get(mid - 1) + values.get(mid)) / 2; - } - - medianObservedWeight = (double) medianObserved / (double) totalTries; - medianExpectedWeight = (double) medianWeight / totalWeight; - - for (Map.Entry e : randomSelection.entrySet()) { - double observed = (((double) e.getValue() / (double) totalTries)); - - double expected; - if (map.get(e.getKey()).getWeight() == 0) { - // if the value is 0 for any key, we make it equal to the first - // non zero value - expected = (double) minWeight / (double) totalWeight; - } else { - expected = (double) map.get(e.getKey()).getWeight() / (double) totalWeight; - } - if (multiplier > 0 && expected > multiplier * medianExpectedWeight) { - expected = multiplier * medianExpectedWeight; - } - // We can't compare these weights because they are derived from - // different - // values. But if we express them as a multiple of the min in each, - // then - // they should be comparable - double expectedMultiple = expected / medianExpectedWeight; - double observedMultiple = observed / medianObservedWeight; - double delta = (Math.abs(expectedMultiple - observedMultiple) / expectedMultiple) * 100; - System.out.println("Key:" + e.getKey() + " Value:" + e.getValue() + " Expected " + expectedMultiple - + " actual " + observedMultiple + " delta " + delta + "%"); - - // the observed should be within 5% of expected - assertTrue("Not doing uniform selection when weights are equal", delta < 5); - } - } - - @Test - public void testSelectionWithSomeZeroWeights() throws Exception { - Map map = new HashMap(); - Map randomSelection = new HashMap(); - int numKeys = 50; - multiplier = 3; - long val = 0L, total = 0L, minWeight = 100L, medianWeight = minWeight; - wRS.setMaxProbabilityMultiplier(multiplier); - for (Integer i = 0; i < numKeys; i++) { - if (i < numKeys / 3) { - val = 0L; - } else if (i < 2 * (numKeys / 3)) { - val = minWeight; - } else { - val = 2 * minWeight; - } - total += val; - map.put(i.toString(), new TestObj(val)); - randomSelection.put(i.toString(), 0); - } - - wRS.updateMap(map); - int totalTries = 1000000; - for (int i = 0; i < totalTries; i++) { - String key = wRS.getNextRandom(); - randomSelection.put(key, randomSelection.get(key) + 1); - } - verifyResult(map, randomSelection, multiplier, minWeight, medianWeight, total, totalTries); - } - - @Test - public void testSelectionWithUnequalWeights() throws Exception { - Map map = new HashMap(); - Map randomSelection = new HashMap(); - int numKeys = 50; - multiplier = 4; - long val = 0L, total = 0L, minWeight = 100L, medianWeight = 2 * minWeight; - wRS.setMaxProbabilityMultiplier(multiplier); - for (Integer i = 0; i < numKeys; i++) { - if (i < numKeys / 3) { - val = minWeight; - } else if (i < 2 * (numKeys / 3)) { - val = 2 * minWeight; - } else { - val = 10 * minWeight; - } - total += val; - map.put(i.toString(), new TestObj(val)); - randomSelection.put(i.toString(), 0); - } - - wRS.updateMap(map); - int totalTries = 1000000; - for (int i = 0; i < totalTries; i++) { - String key = wRS.getNextRandom(); - randomSelection.put(key, randomSelection.get(key) + 1); - } - verifyResult(map, randomSelection, multiplier, minWeight, medianWeight, total, totalTries); - } - - @Test - public void testSelectionWithHotNode() throws Exception { - Map map = new HashMap(); - Map randomSelection = new HashMap(); - - multiplier = 3; // no max - int numKeys = 50; - long total = 0L, minWeight = 100L, val = minWeight, medianWeight = minWeight; - wRS.setMaxProbabilityMultiplier(multiplier); - for (Integer i = 0; i < numKeys; i++) { - if (i == numKeys - 1) { - // last one has 10X more weight than the rest put together - val = 10 * (numKeys - 1) * 100L; - } - total += val; - map.put(i.toString(), new TestObj(val)); - randomSelection.put(i.toString(), 0); - } - - wRS.updateMap(map); - int totalTries = 1000000; - for (int i = 0; i < totalTries; i++) { - String key = wRS.getNextRandom(); - randomSelection.put(key, randomSelection.get(key) + 1); - } - verifyResult(map, randomSelection, multiplier, minWeight, medianWeight, total, totalTries); - } - - @Test - public void testSelectionWithHotNodeWithLimit() throws Exception { - Map map = new HashMap(); - Map randomSelection = new HashMap(); - - multiplier = 3; // limit the max load on hot node to be 3X - int numKeys = 50; - long total = 0L, minWeight = 100L, val = minWeight, medianWeight = minWeight; - wRS.setMaxProbabilityMultiplier(multiplier); - for (Integer i = 0; i < numKeys; i++) { - if (i == numKeys - 1) { - // last one has 10X more weight than the rest put together - val = 10 * (numKeys - 1) * 100L; - } - total += val; - map.put(i.toString(), new TestObj(val)); - randomSelection.put(i.toString(), 0); - } - - wRS.updateMap(map); - int totalTries = 1000000; - for (int i = 0; i < totalTries; i++) { - String key = wRS.getNextRandom(); - randomSelection.put(key, randomSelection.get(key) + 1); - } - verifyResult(map, randomSelection, multiplier, minWeight, medianWeight, total, totalTries); - } - - @Test - public void testSelectionFromSelectedNodesWithEqualWeights() throws Exception { - /* - * this testcase is for only DynamicWeightedRandomSelectionImpl - */ - Assume.assumeTrue(weightedRandomSelectionClass.equals(DynamicWeightedRandomSelectionImpl.class)); - Map map = new HashMap(); - - Long val = 100L; - int numKeys = 50, totalTries = 1000; - Map randomSelection = new HashMap(); - for (Integer i = 0; i < numKeys; i++) { - map.put(i.toString(), new TestObj(val)); - randomSelection.put(i.toString(), 0); - } - - Set selectFrom = new HashSet(); - for (int i = 0; i < numKeys / 2; i++) { - selectFrom.add(Integer.toString(i)); - } - - wRS.updateMap(map); - for (int i = 0; i < totalTries; i++) { - String selectedKey = wRS.getNextRandom(selectFrom); - assertTrue("NextRandom key should be from selected list", selectFrom.contains(selectedKey)); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestZoneawareEnsemblePlacementPolicy.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestZoneawareEnsemblePlacementPolicy.java deleted file mode 100644 index b191225c834..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestZoneawareEnsemblePlacementPolicy.java +++ /dev/null @@ -1,1368 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client; - -import static org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicyImpl.REPP_DNS_RESOLVER_CLASS; -import static org.apache.bookkeeper.client.RoundRobinDistributionSchedule.writeSetFromValues; -import static org.apache.bookkeeper.feature.SettableFeatureProvider.DISABLE_ALL; -import static org.junit.Assert.assertNotEquals; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.netty.util.HashedWheelTimer; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; -import org.apache.bookkeeper.client.BookieInfoReader.BookieInfo; -import org.apache.bookkeeper.client.EnsemblePlacementPolicy.PlacementPolicyAdherence; -import org.apache.bookkeeper.client.EnsemblePlacementPolicy.PlacementResult; -import org.apache.bookkeeper.client.ZoneawareEnsemblePlacementPolicyImpl.ZoneAwareNodeLocation; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.bookkeeper.net.NetworkTopology; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the zoneaware ensemble placement policy. - */ -public class TestZoneawareEnsemblePlacementPolicy extends TestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestZoneawareEnsemblePlacementPolicy.class); - - ZoneawareEnsemblePlacementPolicy zepp; - final List ensemble = new ArrayList(); - DistributionSchedule.WriteSet writeSet = DistributionSchedule.NULL_WRITE_SET; - ClientConfiguration conf = new ClientConfiguration(); - BookieSocketAddress addr1; - BookieSocketAddress addr2, addr3, addr4; - io.netty.util.HashedWheelTimer timer; - - @Override - protected void setUp() throws Exception { - super.setUp(); - StaticDNSResolver.reset(); - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostAddress(), - NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack("127.0.0.1", NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack("localhost", NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - LOG.info("Set up static DNS Resolver."); - conf.setProperty(REPP_DNS_RESOLVER_CLASS, StaticDNSResolver.class.getName()); - addr1 = new BookieSocketAddress("127.0.0.2", 3181); - addr2 = new BookieSocketAddress("127.0.0.3", 3181); - addr3 = new BookieSocketAddress("127.0.0.4", 3181); - addr4 = new BookieSocketAddress("127.0.0.5", 3181); - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), NetworkTopology.DEFAULT_ZONE + "/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), NetworkTopology.DEFAULT_ZONE + "/ud2"); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - ensemble.add(addr4.toBookieId()); - writeSet = writeSetFromValues(0, 1, 2, 3); - - timer = new HashedWheelTimer(new ThreadFactoryBuilder().setNameFormat("TestTimer-%d").build(), - conf.getTimeoutTimerTickDurationMs(), TimeUnit.MILLISECONDS, conf.getTimeoutTimerNumTicks()); - - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(conf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - } - - @Override - protected void tearDown() throws Exception { - zepp.uninitalize(); - super.tearDown(); - } - - static BookiesHealthInfo getBookiesHealthInfo() { - return getBookiesHealthInfo(new HashMap<>(), new HashMap<>()); - } - - static BookiesHealthInfo getBookiesHealthInfo(Map bookieFailureHistory, - Map bookiePendingRequests) { - return new BookiesHealthInfo() { - @Override - public long getBookieFailureHistory(BookieId bookieSocketAddress) { - return bookieFailureHistory.getOrDefault(bookieSocketAddress, -1L); - } - - @Override - public long getBookiePendingRequests(BookieId bookieSocketAddress) { - return bookiePendingRequests.getOrDefault(bookieSocketAddress, 0L); - } - }; - } - - static void updateMyUpgradeDomain(String zoneAndUD) throws Exception { - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostAddress(), zoneAndUD); - StaticDNSResolver.addNodeToRack(InetAddress.getLocalHost().getHostName(), zoneAndUD); - StaticDNSResolver.addNodeToRack("127.0.0.1", zoneAndUD); - StaticDNSResolver.addNodeToRack("localhost", zoneAndUD); - } - - @Test - public void testNotEnoughRWBookies() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone4/ud1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone5/ud1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone6/ud1"); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(1); - newConf.setMinNumZonesPerWriteQuorum(1); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - try { - // only 3 rw bookies are available - zepp.newEnsemble(6, 3, 2, null, new HashSet<>()); - fail("newEnsemble is expected to fail because enough writable nodes are not available"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // expected to get BKNotEnoughBookiesException - } - - roAddrs.add(addr4.toBookieId()); - roAddrs.add(addr5.toBookieId()); - roAddrs.add(addr6.toBookieId()); - zepp.onClusterChanged(rwAddrs, roAddrs); - try { - // only 3 rw bookies are available - zepp.newEnsemble(6, 3, 2, null, new HashSet<>()); - fail("newEnsemble is expected to fail because enough writable nodes are not available"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // expected to get BKNotEnoughBookiesException - } - - rwAddrs.clear(); - roAddrs.add(addr1.toBookieId()); - roAddrs.add(addr2.toBookieId()); - roAddrs.add(addr3.toBookieId()); - zepp.onClusterChanged(rwAddrs, roAddrs); - try { - // no rw bookie is available - zepp.newEnsemble(6, 3, 2, null, new HashSet<>()); - fail("newEnsemble is expected to fail because enough writable nodes are not available"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // expected to get BKNotEnoughBookiesException - } - } - - @Test - public void testEnoughRWBookies() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone4/ud1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone5/ud1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone6/ud1"); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(2); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - /* - * there are enough bookies so newEnsemble should succeed. - */ - PlacementResult> newEnsemblePlacementResult = zepp.newEnsemble(6, 3, 2, null, - new HashSet<>()); - Set newEnsembleSet = new HashSet( - newEnsemblePlacementResult.getResult()); - assertTrue("New ensemble should contain all 6 rw bookies", newEnsembleSet.containsAll(rwAddrs)); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - newEnsemblePlacementResult.getAdheringToPolicy()); - - /* - * there are enough bookies so newEnsemble should succeed. - */ - newEnsemblePlacementResult = zepp.newEnsemble(3, 3, 2, null, new HashSet<>()); - newEnsembleSet = new HashSet(newEnsemblePlacementResult.getResult()); - assertTrue("New ensemble should contain 3 rw bookies", - (newEnsembleSet.size() == 3) && (rwAddrs.containsAll(newEnsembleSet))); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - newEnsemblePlacementResult.getAdheringToPolicy()); - } - - @Test - public void testWithDefaultBookies() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone4/ud1"); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - Set bookiesInDefaultFaultDomain = new HashSet(); - bookiesInDefaultFaultDomain.add(addr5.toBookieId()); - bookiesInDefaultFaultDomain.add(addr6.toBookieId()); - bookiesInDefaultFaultDomain.add(addr7.toBookieId()); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr7.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - for (int i = 0; i < 3; i++) { - /* - * make sure bookies from DEFAULT_ZONE_AND_UPGRADEDOMAIN are not - * part of the new ensemble created. - */ - PlacementResult> newEnsemblePlacementResult = zepp.newEnsemble(4, 4, 2, null, - new HashSet<>()); - Set newEnsembleSet = new HashSet( - newEnsemblePlacementResult.getResult()); - assertTrue("Bookie from default faultDomain shouldn't be part of ensemble", - Collections.disjoint(newEnsembleSet, bookiesInDefaultFaultDomain)); - - newEnsemblePlacementResult = zepp.newEnsemble(3, 3, 2, null, new HashSet<>()); - newEnsembleSet = new HashSet(newEnsemblePlacementResult.getResult()); - assertTrue("Bookie from default faultDomain shouldn't be part of ensemble", - Collections.disjoint(newEnsembleSet, bookiesInDefaultFaultDomain)); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - newEnsemblePlacementResult.getAdheringToPolicy()); - } - } - - @Test - public void testMinZonesPerWriteQuorum() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone1/ud3"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone2/ud3"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(3); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - Set bookiesInDefaultFaultDomain = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr9.toBookieId()); - rwAddrs.add(addr10.toBookieId()); - roAddrs.add(addr7.toBookieId()); - roAddrs.add(addr8.toBookieId()); - bookiesInDefaultFaultDomain.add(addr9.toBookieId()); - bookiesInDefaultFaultDomain.add(addr10.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - PlacementResult> newEnsemblePlacementResult; - - newEnsemblePlacementResult = zepp.newEnsemble(4, 4, 2, null, new HashSet<>()); - Set newEnsembleSet = new HashSet( - newEnsemblePlacementResult.getResult()); - assertTrue("New ensemble should contain all 6 rw bookies in non-default fault domains", - rwAddrs.containsAll(newEnsembleSet) && (newEnsembleSet.size() == 4)); - assertTrue("Bookie from default faultDomain shouldn't be part of ensemble", - Collections.disjoint(newEnsembleSet, bookiesInDefaultFaultDomain)); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_SOFT, - newEnsemblePlacementResult.getAdheringToPolicy()); - - try { - /* - * If ensembleSize is not multiple of writeQuorumSize, then it is - * expected to fail with IllegalArgumentException. - */ - zepp.newEnsemble(4, 3, 2, null, new HashSet<>()); - fail("newEnsemble is expected to fail with IllegalArgumentException"); - } catch (IllegalArgumentException illExc) { - // expected IllegalArgumentException - } - zepp.uninitalize(); - newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(3); - newConf.setEnforceStrictZoneawarePlacement(false); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - zepp.onClusterChanged(rwAddrs, roAddrs); - - /* - * If enforceStrictZoneawarePlacement is not enabled, then there are no - * limitations on eligible values of ensembleSize and writeQuorumSize. - */ - newEnsemblePlacementResult = zepp.newEnsemble(4, 3, 2, null, new HashSet<>()); - newEnsembleSet = new HashSet(newEnsemblePlacementResult.getResult()); - assertTrue("New ensemble should contain 4 different bookies", newEnsembleSet.size() == 4); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - newEnsemblePlacementResult.getAdheringToPolicy()); - } - - @Test - public void testMinUDsNotAvailable() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone1/ud3"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone2/ud3"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(2); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - Set bookiesInDefaultFaultDomain = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr9.toBookieId()); - rwAddrs.add(addr10.toBookieId()); - - roAddrs.add(addr7.toBookieId()); - roAddrs.add(addr8.toBookieId()); - - bookiesInDefaultFaultDomain.add(addr9.toBookieId()); - bookiesInDefaultFaultDomain.add(addr10.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - PlacementResult> newEnsemblePlacementResult; - try { - /* - * since rw bookies are not spread across UDs in zones, newEnsemble - * of writeQuorum 6 is expected to fail. - */ - zepp.newEnsemble(6, 6, 2, null, new HashSet<>()); - fail("newEnsemble is expected to fail because writeQuorum cannt be created with insufficient UDs"); - } catch (BKException.BKNotEnoughBookiesException bkne) { - // expected NotEnoughBookiesException - } - - int ensSize = 6; - int writeQuorum = 3; - /* - * though bookies are not spread across UDs in zones, newEnsemble would - * succeed because writeQuorum is just 3. - */ - newEnsemblePlacementResult = zepp.newEnsemble(ensSize, writeQuorum, 2, null, new HashSet<>()); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - newEnsemblePlacementResult.getAdheringToPolicy()); - List newEnsemble = newEnsemblePlacementResult.getResult(); - Set newEnsembleSet = new HashSet(newEnsemble); - assertTrue("New ensemble should contain all 6 rw bookies in non-default fault domains", - rwAddrs.containsAll(newEnsembleSet) && (newEnsembleSet.size() == 6)); - assertTrue("Bookie from default faultDomain shouldn't be part of ensemble", - Collections.disjoint(newEnsembleSet, bookiesInDefaultFaultDomain)); - - Set zonesOfBookiesInAWriteQuorum = new HashSet(); - for (int i = 0; i < 6; i++) { - zonesOfBookiesInAWriteQuorum.clear(); - for (int j = 0; j < writeQuorum; j++) { - zonesOfBookiesInAWriteQuorum - .add(zepp.getZoneAwareNodeLocation(newEnsemble.get((i + j) % ensSize)).getZone()); - } - assertEquals("Since bookies are not spread across multiple UDs in a zone, write quorum should" - + " contain bookies from all 3 zones", 3, zonesOfBookiesInAWriteQuorum.size()); - } - } - - @Test - public void testUniqueUds() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - BookieSocketAddress addr11 = new BookieSocketAddress("127.0.0.12", 3181); - BookieSocketAddress addr12 = new BookieSocketAddress("127.0.0.13", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone1/ud3"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone1/ud3"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr11.getHostName(), "/zone2/ud3"); - StaticDNSResolver.addNodeToRack(addr12.getHostName(), "/zone2/ud3"); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(2); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr7.toBookieId()); - rwAddrs.add(addr8.toBookieId()); - rwAddrs.add(addr9.toBookieId()); - rwAddrs.add(addr10.toBookieId()); - rwAddrs.add(addr11.toBookieId()); - rwAddrs.add(addr12.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - /* - * Since there are enough bookies in different UDs in 2 zones - * (MinNumZonesPerWriteQuorum), new ensemble should succeed. - */ - PlacementResult> newEnsemblePlacementResult = zepp.newEnsemble(6, 6, 2, null, - new HashSet<>()); - List newEnsembleList = newEnsemblePlacementResult.getResult(); - Set newEnsembleSet = new HashSet(newEnsembleList); - assertTrue("New ensemble should contain 6 rw bookies in non-default fault domains", - rwAddrs.containsAll(newEnsembleSet) && (newEnsembleSet.size() == 6)); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_SOFT, - newEnsemblePlacementResult.getAdheringToPolicy()); - Set bookiesNetworkLocations = new HashSet(); - - for (BookieId bookieAddr : newEnsembleSet) { - bookiesNetworkLocations.add(zepp.resolveNetworkLocation(bookieAddr)); - } - /* - * Since there are enough bookies in different UDs, bookies from same - * zone should be from different UDs. - */ - assertTrue("Bookies should be from different UpgradeDomains if they belong to same zone", - (bookiesNetworkLocations.size() == 6)); - List bookiesNodeLocationList = new ArrayList(); - for (BookieId bookieAddr : newEnsembleList) { - bookiesNodeLocationList.add(zepp.getZoneAwareNodeLocation(bookieAddr)); - } - for (int i = 0; i < 5; i++) { - /* - * in newEnsemble order, bookies should be from alternating zones. - */ - assertNotEquals("Alternate bookies should be from different zones", - bookiesNodeLocationList.get(i).getZone(), bookiesNodeLocationList.get(i + 1).getZone()); - } - } - - @Test - public void testNewBookieUniformDistributionWithMinZoneAndMinUDs() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - BookieSocketAddress addr11 = new BookieSocketAddress("127.0.0.12", 3181); - BookieSocketAddress addr12 = new BookieSocketAddress("127.0.0.13", 3181); - BookieSocketAddress addr13 = new BookieSocketAddress("127.0.0.14", 3181); - BookieSocketAddress addr14 = new BookieSocketAddress("127.0.0.15", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr11.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr12.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr13.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr14.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr7.toBookieId()); - rwAddrs.add(addr8.toBookieId()); - rwAddrs.add(addr9.toBookieId()); - rwAddrs.add(addr10.toBookieId()); - rwAddrs.add(addr11.toBookieId()); - rwAddrs.add(addr12.toBookieId()); - rwAddrs.add(addr13.toBookieId()); - rwAddrs.add(addr14.toBookieId()); - - int minNumZonesPerWriteQuorum = 3; - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(5); - newConf.setMinNumZonesPerWriteQuorum(minNumZonesPerWriteQuorum); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - zepp.onClusterChanged(rwAddrs, roAddrs); - Set excludedBookies = new HashSet(); - - PlacementResult> newEnsemblePlacementResult = zepp.newEnsemble(6, 6, 4, null, - excludedBookies); - List newEnsembleList = newEnsemblePlacementResult.getResult(); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_SOFT, - newEnsemblePlacementResult.getAdheringToPolicy()); - Set newEnsembleSet = new HashSet(newEnsembleList); - Set bookiesNetworkLocationsSet = new HashSet(); - List bookiesNodeLocationList = new ArrayList(); - for (BookieId bookieAddr : newEnsembleSet) { - bookiesNetworkLocationsSet.add(zepp.resolveNetworkLocation(bookieAddr)); - } - for (BookieId bookieAddr : newEnsembleList) { - bookiesNodeLocationList.add(zepp.getZoneAwareNodeLocation(bookieAddr)); - } - /* - * since there are enough bookies from minNumZonesPerWriteQuorum (3), - * bookies should be from 3 different zones and 2 different UDs. - */ - assertTrue("Bookies should be from different UpgradeDomains if they belong to same zone", - (bookiesNetworkLocationsSet.size() == 6)); - Set zonesOfFirstNodes = new HashSet(); - for (int i = 0; i < minNumZonesPerWriteQuorum; i++) { - zonesOfFirstNodes.add(bookiesNodeLocationList.get(i).getZone()); - } - assertEquals("Num of zones", minNumZonesPerWriteQuorum, zonesOfFirstNodes.size()); - for (int i = 0; i < minNumZonesPerWriteQuorum; i++) { - assertEquals("Zone", bookiesNodeLocationList.get(i).getZone(), - bookiesNodeLocationList.get(i + minNumZonesPerWriteQuorum).getZone()); - assertNotEquals("UpgradeDomain", bookiesNodeLocationList.get(i).getUpgradeDomain(), - bookiesNodeLocationList.get(i + minNumZonesPerWriteQuorum).getUpgradeDomain()); - } - } - - @Test - public void testReplaceBookie() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - BookieSocketAddress addr11 = new BookieSocketAddress("127.0.0.12", 3181); - BookieSocketAddress addr12 = new BookieSocketAddress("127.0.0.13", 3181); - BookieSocketAddress addr13 = new BookieSocketAddress("127.0.0.14", 3181); - BookieSocketAddress addr14 = new BookieSocketAddress("127.0.0.15", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr11.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr12.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr13.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr14.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(3); - newConf.setMinNumZonesPerWriteQuorum(3); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr7.toBookieId()); - rwAddrs.add(addr8.toBookieId()); - rwAddrs.add(addr9.toBookieId()); - rwAddrs.add(addr10.toBookieId()); - rwAddrs.add(addr11.toBookieId()); - rwAddrs.add(addr12.toBookieId()); - rwAddrs.add(addr13.toBookieId()); - rwAddrs.add(addr14.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - List ensemble = new ArrayList(); - Set excludedBookies = new HashSet(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr5.toBookieId()); - ensemble.add(addr9.toBookieId()); - ensemble.add(addr3.toBookieId()); - ensemble.add(addr7.toBookieId()); - ensemble.add(addr11.toBookieId()); - /* - * since addr5 (/zone2/ud1) is already part of ensemble of size 6, write - * quorum of size 6, to replace bookie addr7 (/zone2/ud2), new bookie - * should be from /zone2/ud2. - */ - PlacementResult replacePlacementResult = zepp.replaceBookie(6, 6, 2, null, ensemble, - addr7.toBookieId(), - excludedBookies); - BookieId replacedBookie = replacePlacementResult.getResult(); - assertEquals("replaced bookie", addr8.toBookieId(), replacedBookie); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - replacePlacementResult.getAdheringToPolicy()); - - excludedBookies.add(addr8.toBookieId()); - /* - * here addr8 is excluded, and writeQuorumSize is 3. So to replace - * bookie addr7, addr6 (belonging to same zone) is the candidate. - */ - replacePlacementResult = zepp.replaceBookie(6, 3, 2, null, ensemble, addr7.toBookieId(), - excludedBookies); - replacedBookie = replacePlacementResult.getResult(); - assertEquals("replaced bookie", addr6.toBookieId(), replacedBookie); - - excludedBookies.add(addr6.toBookieId()); - try { - /* - * here addr6 is also excluded, so replaceBookie should fail. - */ - replacedBookie = zepp.replaceBookie(6, 3, 2, null, ensemble, addr7.toBookieId(), excludedBookies) - .getResult(); - fail("Expected BKNotEnoughBookiesException for replaceBookie with added excludedBookies"); - } catch (BKException.BKNotEnoughBookiesException bkne) { - // expected NotEnoughBookiesException - } - } - - @Test - public void testReplaceBookieMinUDs() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - BookieSocketAddress addr11 = new BookieSocketAddress("127.0.0.12", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr11.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(3); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr7.toBookieId()); - rwAddrs.add(addr8.toBookieId()); - rwAddrs.add(addr9.toBookieId()); - rwAddrs.add(addr10.toBookieId()); - rwAddrs.add(addr11.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - List ensemble = new ArrayList(); - Set excludedBookies = new HashSet(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr5.toBookieId()); - ensemble.add(addr6.toBookieId()); - /* - * though all the remaining non-default bookies are in /zone3/ud2, for - * replacing addr4 replaceBookie should be able to find some other - * bookie in /zone3/ud2. - */ - PlacementResult replaceResponse = zepp.replaceBookie(6, 6, 2, null, ensemble, addr4.toBookieId(), - excludedBookies); - BookieId replacedBookie = replaceResponse.getResult(); - assertEquals("replaced bookie", "/zone3/ud2", zepp.resolveNetworkLocation(replacedBookie)); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_SOFT, - replaceResponse.getAdheringToPolicy()); - } - - @Test - public void testAreAckedBookiesAdheringToPlacementPolicy() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone1/ud3"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone2/ud3"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/zone3/ud3"); - - ClientConfiguration newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(2); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr6.toBookieId()); - rwAddrs.add(addr7.toBookieId()); - rwAddrs.add(addr8.toBookieId()); - rwAddrs.add(addr9.toBookieId()); - - zepp.onClusterChanged(rwAddrs, roAddrs); - Set ackedBookies = new HashSet(); - ackedBookies.add(addr1.toBookieId()); - ackedBookies.add(addr4.toBookieId()); - assertFalse("since both the bookies are in the same zone, it should return false", - zepp.areAckedBookiesAdheringToPlacementPolicy(ackedBookies, 10, 2)); - ackedBookies.clear(); - ackedBookies.add(addr1.toBookieId()); - ackedBookies.add(addr2.toBookieId()); - assertFalse("since ackQuorumSize is 3, it should return false", - zepp.areAckedBookiesAdheringToPlacementPolicy(ackedBookies, 10, 3)); - assertTrue("since ackQuorumSize is 2 and bookies are from minNumZonesPerWriteQuorum it should return true", - zepp.areAckedBookiesAdheringToPlacementPolicy(ackedBookies, 10, 2)); - - zepp.uninitalize(); - newConf = (ClientConfiguration) this.conf.clone(); - newConf.setDesiredNumZonesPerWriteQuorum(4); - newConf.setMinNumZonesPerWriteQuorum(4); - zepp = new ZoneawareEnsemblePlacementPolicy(); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - zepp.onClusterChanged(rwAddrs, roAddrs); - ackedBookies.clear(); - ackedBookies.add(addr1.toBookieId()); - ackedBookies.add(addr2.toBookieId()); - ackedBookies.add(addr3.toBookieId()); - assertFalse("since minNumZonesPerWriteQuorum is set to 4, it should return false", - zepp.areAckedBookiesAdheringToPlacementPolicy(ackedBookies, 4, 3)); - assertTrue("since writeQuorumSize is set to 3, it should return true", - zepp.areAckedBookiesAdheringToPlacementPolicy(ackedBookies, 3, 3)); - ackedBookies.clear(); - ackedBookies.add(addr1.toBookieId()); - ackedBookies.add(addr2.toBookieId()); - ackedBookies.add(addr4.toBookieId()); - assertFalse("since bookies are in just 2 zones but not in 3 zones, it should return false", - zepp.areAckedBookiesAdheringToPlacementPolicy(ackedBookies, 3, 3)); - } - - @Test - public void testWeightedPlacement() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - // Update cluster - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - addrs.add(addr5.toBookieId()); - - int multiple = 10; - - ClientConfiguration newConf = new ClientConfiguration(conf); - newConf.addConfiguration(conf); - newConf.setDiskWeightBasedPlacementEnabled(true); - /* - * since BookieMaxWeightMultipleForWeightBasedPlacement is set to -1, - * there is no max cap on weight. - */ - newConf.setBookieMaxWeightMultipleForWeightBasedPlacement(-1); - newConf.setMinNumZonesPerWriteQuorum(0); - zepp.initialize(newConf, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - zepp.onClusterChanged(addrs, new HashSet()); - Map bookieInfoMap = new HashMap(); - bookieInfoMap.put(addr1.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr2.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr3.toBookieId(), new BookieInfo(100L, 100L)); - bookieInfoMap.put(addr4.toBookieId(), new BookieInfo(multiple * 100L, multiple * 100L)); - bookieInfoMap.put(addr5.toBookieId(), new BookieInfo(100L, 100L)); - zepp.updateBookieInfo(bookieInfoMap); - - Map selectionCounts = new HashMap(); - int numTries = 50000; - EnsemblePlacementPolicy.PlacementResult> newEnsembleResponse; - List newEnsemble; - for (BookieId addr : addrs) { - selectionCounts.put(addr, (long) 0); - } - for (int i = 0; i < numTries; i++) { - // new ensemble response - newEnsembleResponse = zepp.newEnsemble(1, 1, 1, null, new HashSet()); - newEnsemble = newEnsembleResponse.getResult(); - selectionCounts.put(newEnsemble.get(0), selectionCounts.get(newEnsemble.get(0)) + 1); - } - double observedMultiple = ((double) selectionCounts.get(addr4.toBookieId()) - / (double) selectionCounts.get(addr3.toBookieId())); - /* - * since there is no cap on maxWeight, observedMultiple should be - * roughly equal to multiple - */ - assertTrue("Weights not being honored " + observedMultiple, Math.abs(observedMultiple - multiple) < 1); - - selectionCounts.clear(); - selectionCounts.put(addr3.toBookieId(), (long) 0); - selectionCounts.put(addr4.toBookieId(), (long) 0); - newEnsemble = new ArrayList(); - newEnsemble.add(addr2.toBookieId()); - Set excludedBookies = new HashSet(); - excludedBookies.add(addr1.toBookieId()); - EnsemblePlacementPolicy.PlacementResult replacedBookieResponse; - BookieId replacedBookie; - for (int i = 0; i < numTries; i++) { - // replace bookie response - replacedBookieResponse = zepp.replaceBookie(1, 1, 1, null, newEnsemble, addr2.toBookieId(), - excludedBookies); - replacedBookie = replacedBookieResponse.getResult(); - /* - * only addr3 and addr4 are eligible for replacedBookie. - */ - assertTrue("replaced : " + replacedBookie, addr3.toBookieId().equals(replacedBookie) - || addr4.toBookieId().equals(replacedBookie)); - selectionCounts.put(replacedBookie, selectionCounts.get(replacedBookie) + 1); - } - observedMultiple = ((double) selectionCounts.get(addr4.toBookieId()) - / (double) selectionCounts.get(addr3.toBookieId())); - /* - * since there is no cap on maxWeight, observedMultiple should be - * roughly equal to multiple - */ - assertTrue("Weights not being honored " + observedMultiple, Math.abs(observedMultiple - multiple) < 1); - } - - @Test - public void testPlacementOnStabilizeNetworkTopology() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone4/ud1"); - - zepp = new ZoneawareEnsemblePlacementPolicy(); - ClientConfiguration confLocal = new ClientConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setNetworkTopologyStabilizePeriodSeconds(99999); - zepp.initialize(confLocal, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set addrs = new HashSet(); - addrs.add(addr1.toBookieId()); - addrs.add(addr2.toBookieId()); - addrs.add(addr3.toBookieId()); - addrs.add(addr4.toBookieId()); - zepp.onClusterChanged(addrs, new HashSet()); - // addr4 left - addrs.remove(addr4.toBookieId()); - Set deadBookies = zepp.onClusterChanged(addrs, new HashSet()); - assertTrue(deadBookies.isEmpty()); - - // we will never use addr4 even it is in the stabilized network topology - for (int i = 0; i < 5; i++) { - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = zepp.newEnsemble(3, 3, - 2, null, new HashSet()); - List ensemble = ensembleResponse.getResult(); - assertFalse(ensemble.contains(addr4.toBookieId())); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - ensembleResponse.getAdheringToPolicy()); - } - - // we could still use addr4 for urgent allocation if it is just bookie - // flapping - EnsemblePlacementPolicy.PlacementResult> ensembleResponse = zepp.newEnsemble(4, 4, 2, - null, new HashSet()); - List ensemble = ensembleResponse.getResult(); - assertTrue(ensemble.contains(addr4.toBookieId())); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - ensembleResponse.getAdheringToPolicy()); - } - - @Test - public void testCreateNewEnsembleRandomly() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone1/ud1"); - - zepp = new ZoneawareEnsemblePlacementPolicy(); - ClientConfiguration confLocal = new ClientConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setEnforceStrictZoneawarePlacement(false); - confLocal.setMinNumZonesPerWriteQuorum(3); - confLocal.setDesiredNumZonesPerWriteQuorum(4); - zepp.initialize(confLocal, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - Set excludeBookies = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - excludeBookies.add(addr5.toBookieId()); - zepp.onClusterChanged(rwAddrs, roAddrs); - /* - * if enforceStrictZoneawarePlacement is not enabled, then there is no - * restrictions on ensSize and writeQSize and also bookie belonging to - * DEFAULT_ZONE_AND_UPGRADEDOMAIN can be a candidate. - */ - PlacementResult> newEnsemblePlacementResult = zepp.newEnsemble(4, 3, 2, null, - excludeBookies); - Set newEnsembleSet = new HashSet( - newEnsemblePlacementResult.getResult()); - assertEquals("New ensemble should contain 4 rw bookies", 4, newEnsembleSet.size()); - assertFalse("excludeBookie should not be included in the ensemble", - newEnsembleSet.contains(addr5.toBookieId())); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - newEnsemblePlacementResult.getAdheringToPolicy()); - - rwAddrs.remove(addr4.toBookieId()); - roAddrs.add(addr4.toBookieId()); - zepp.onClusterChanged(rwAddrs, roAddrs); - try { - /* - * since there is no bookie available, newEnsemble should fail. - */ - zepp.newEnsemble(4, 3, 2, null, excludeBookies); - fail("Creation of new ensemble randomly should fail because of not sufficient bookies"); - } catch (BKException.BKNotEnoughBookiesException bkne) { - // expected NotEnoughBookiesException - } - } - - @Test - public void testReplaceBookieRandomly() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - zepp = new ZoneawareEnsemblePlacementPolicy(); - ClientConfiguration confLocal = new ClientConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setEnforceStrictZoneawarePlacement(false); - confLocal.setMinNumZonesPerWriteQuorum(3); - confLocal.setDesiredNumZonesPerWriteQuorum(4); - zepp.initialize(confLocal, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - Set rwAddrs = new HashSet(); - Set roAddrs = new HashSet(); - Set excludeBookies = new HashSet(); - rwAddrs.add(addr1.toBookieId()); - rwAddrs.add(addr2.toBookieId()); - rwAddrs.add(addr3.toBookieId()); - rwAddrs.add(addr4.toBookieId()); - rwAddrs.add(addr5.toBookieId()); - rwAddrs.add(addr7.toBookieId()); - - roAddrs.add(addr6.toBookieId()); - excludeBookies.add(addr5.toBookieId()); - zepp.onClusterChanged(rwAddrs, roAddrs); - List ensembleList = new ArrayList(); - ensembleList.add(addr1.toBookieId()); - ensembleList.add(addr2.toBookieId()); - ensembleList.add(addr3.toBookieId()); - ensembleList.add(addr4.toBookieId()); - - PlacementResult replaceResponse = zepp.replaceBookie(4, 3, 2, null, ensembleList, addr3.toBookieId(), - excludeBookies); - BookieId replaceBookie = replaceResponse.getResult(); - /* - * if enforceStrictZoneawarePlacement is not enabled, then there is no - * restrictions on ensSize and writeQSize and also bookie belonging to - * DEFAULT_ZONE_AND_UPGRADEDOMAIN can be a candidate. - */ - assertEquals("ReplaceBookie candidate", addr7.toBookieId(), replaceBookie); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - replaceResponse.getAdheringToPolicy()); - - rwAddrs.remove(addr7.toBookieId()); - excludeBookies.add(addr7.toBookieId()); - zepp.onClusterChanged(rwAddrs, roAddrs); - try { - /* - * since there is no bookie available, replaceBookie should fail. - */ - zepp.replaceBookie(4, 3, 2, null, ensembleList, addr3.toBookieId(), excludeBookies); - fail("ReplaceBookie should fail because of unavailable bookies"); - } catch (BKException.BKNotEnoughBookiesException bkne) { - // expected NotEnoughBookiesException - } - } - - @Test - public void testIsEnsembleAdheringToPlacementPolicy() throws Exception { - zepp.uninitalize(); - updateMyUpgradeDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - // Update cluster - BookieSocketAddress addr5 = new BookieSocketAddress("127.0.0.6", 3181); - BookieSocketAddress addr6 = new BookieSocketAddress("127.0.0.7", 3181); - BookieSocketAddress addr7 = new BookieSocketAddress("127.0.0.8", 3181); - BookieSocketAddress addr8 = new BookieSocketAddress("127.0.0.9", 3181); - BookieSocketAddress addr9 = new BookieSocketAddress("127.0.0.10", 3181); - BookieSocketAddress addr10 = new BookieSocketAddress("127.0.0.11", 3181); - - // update dns mapping - StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/zone1/ud1"); - StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/zone1/ud2"); - StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/zone2/ud1"); - StaticDNSResolver.addNodeToRack(addr5.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr6.getHostName(), "/zone2/ud2"); - StaticDNSResolver.addNodeToRack(addr7.getHostName(), "/zone3/ud1"); - StaticDNSResolver.addNodeToRack(addr8.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr9.getHostName(), "/zone3/ud2"); - StaticDNSResolver.addNodeToRack(addr10.getHostName(), NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - zepp = new ZoneawareEnsemblePlacementPolicy(); - ClientConfiguration confLocal = new ClientConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setEnforceStrictZoneawarePlacement(true); - confLocal.setMinNumZonesPerWriteQuorum(2); - confLocal.setDesiredNumZonesPerWriteQuorum(3); - zepp.initialize(confLocal, Optional. empty(), timer, DISABLE_ALL, - NullStatsLogger.INSTANCE, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - zepp.withDefaultFaultDomain(NetworkTopology.DEFAULT_ZONE_AND_UPGRADEDOMAIN); - - List emptyEnsmeble = new ArrayList<>(); - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - zepp.isEnsembleAdheringToPlacementPolicy(emptyEnsmeble, 3, 2)); - - List ensemble = new ArrayList(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - // all bookies in same rack - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr4.toBookieId()); - // bookies spread across minZones - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_SOFT, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr7.toBookieId()); - // bookies spread across desirednumofzones - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr4.toBookieId()); - // writeQuorum should be greater than minZones - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 2, 2)); - - ensemble.clear(); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr3.toBookieId()); - ensemble.add(addr4.toBookieId()); - // bookies from zone1 (addr2 and addr3) are in same UD - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr7.toBookieId()); - ensemble.add(addr10.toBookieId()); - // bookie from default faultdomain will cause PlacementPolicyAdherence - // to fail - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 4, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr7.toBookieId()); - ensemble.add(addr8.toBookieId()); - ensemble.add(addr9.toBookieId()); - // bookies are spread across desired zones and bookie from same zone are - // spread across 2 UDs - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_STRICT, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 5, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr7.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr8.toBookieId()); - ensemble.add(addr9.toBookieId()); - /* - * writeset of addr2, addr8 and addr9 fails, because addr8 and addr9 - * belong to z3u2 - */ - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr9.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr8.toBookieId()); - ensemble.add(addr7.toBookieId()); - /* - * writeset of addr9, addr2 and addr8 fails, because addr8 and addr9 - * belong to z3u2 - */ - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.FAIL, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 2)); - - ensemble.clear(); - ensemble.add(addr1.toBookieId()); - ensemble.add(addr4.toBookieId()); - ensemble.add(addr9.toBookieId()); - ensemble.add(addr2.toBookieId()); - ensemble.add(addr7.toBookieId()); - ensemble.add(addr8.toBookieId()); - /* - * writeset of addr2, addr7 and addr8 just meets soft. - */ - assertEquals("PlacementPolicyAdherence", PlacementPolicyAdherence.MEETS_SOFT, - zepp.isEnsembleAdheringToPlacementPolicy(ensemble, 3, 2)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerCmdTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerCmdTest.java deleted file mode 100644 index e9c2fb69a52..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerCmdTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieShell; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.zookeeper.KeeperException; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test an update command on a ledger. - */ -public class UpdateLedgerCmdTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(UpdateLedgerCmdTest.class); - private DigestType digestType = DigestType.CRC32; - private static final String PASSWORD = "testPasswd"; - - public UpdateLedgerCmdTest() { - super(3); - useUUIDasBookieId = false; - baseConf.setGcWaitTime(100000); - } - - /** - * updateledgers to hostname. - */ - @Test - public void testUpdateLedgersToHostname() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - List ledgers = new ArrayList(); - LedgerHandle lh1 = createLedgerWithEntries(bk, 0); - ledgers.add(lh1); - for (int i = 1; i < 40; i++) { - ledgers.add(createLedgerWithEntries(bk, 0)); - } - - String[] argv = new String[] { "updateledgers", "-b", "hostname", "-v", "true", "-p", "2" }; - final ServerConfiguration conf = confByIndex(0); - conf.setUseHostNameAsBookieID(true); - BookieSocketAddress toBookieId = BookieImpl.getBookieAddress(conf); - BookieId toBookieAddr = new BookieSocketAddress(toBookieId.getHostName() + ":" - + conf.getBookiePort()).toBookieId(); - updateLedgerCmd(argv, 0, conf); - - int updatedLedgersCount = getUpdatedLedgersCount(bk, ledgers, toBookieAddr); - assertEquals("Failed to update the ledger metadata to use bookie host name", 40, updatedLedgersCount); - } - - /** - * replace bookie address in ledger. - */ - @Test - public void testUpdateBookieInLedger() throws Exception { - BookKeeper bk = new BookKeeper(baseClientConf, zkc); - LOG.info("Create ledger and add entries to it"); - List ledgers = new ArrayList(); - LedgerHandle lh1 = createLedgerWithEntries(bk, 0); - ledgers.add(lh1); - for (int i = 1; i < 40; i++) { - ledgers.add(createLedgerWithEntries(bk, 0)); - } - BookieId srcBookie = getBookie(0); - BookieId destBookie = new BookieSocketAddress("1.1.1.1", 2181).toBookieId(); - String[] argv = new String[] { "updateBookieInLedger", "-sb", srcBookie.toString(), "-db", - destBookie.toString(), "-v", "true", "-p", "2" }; - final ServerConfiguration conf = confByIndex(0); - killBookie(0); - updateLedgerCmd(argv, 0, conf); - int updatedLedgersCount = getUpdatedLedgersCount(bk, ledgers, srcBookie); - assertEquals("Failed to update the ledger metadata with new bookie-address", 0, updatedLedgersCount); - updatedLedgersCount = getUpdatedLedgersCount(bk, ledgers, destBookie); - assertEquals("Failed to update the ledger metadata with new bookie-address", 40, updatedLedgersCount); - } - - private void updateLedgerCmd(String[] argv, int exitCode, ServerConfiguration conf) throws KeeperException, - InterruptedException, IOException, UnknownHostException, Exception { - LOG.info("Perform updateledgers command"); - BookieShell bkShell = new BookieShell(); - bkShell.setConf(conf); - - assertEquals("Failed to return exit code!", exitCode, bkShell.run(argv)); - } - - private int getUpdatedLedgersCount(BookKeeper bk, List ledgers, BookieId toBookieAddr) - throws InterruptedException, BKException { - List ensemble; - int updatedLedgersCount = 0; - for (LedgerHandle lh : ledgers) { - lh.close(); - LedgerHandle openLedger = bk.openLedger(lh.getId(), digestType, PASSWORD.getBytes()); - ensemble = openLedger.getLedgerMetadata().getEnsembleAt(0); - if (ensemble.contains(toBookieAddr)) { - updatedLedgersCount++; - } - } - return updatedLedgersCount; - } - - private LedgerHandle createLedgerWithEntries(BookKeeper bk, int numOfEntries) throws Exception { - LedgerHandle lh = bk.createLedger(3, 3, digestType, PASSWORD.getBytes()); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - final CountDownLatch latch = new CountDownLatch(numOfEntries); - - final AddCallback cb = new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - latch.countDown(); - } - }; - for (int i = 0; i < numOfEntries; i++) { - lh.asyncAddEntry(("foobar" + i).getBytes(), cb, null); - } - if (!latch.await(30, TimeUnit.SECONDS)) { - throw new Exception("Entries took too long to add"); - } - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - return lh; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerOpTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerOpTest.java deleted file mode 100644 index 806ee9359f8..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerOpTest.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieShell.UpdateLedgerNotifier; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.MathUtils; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test update operations on a ledger. - */ -public class UpdateLedgerOpTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(UpdateLedgerOpTest.class); - private DigestType digestType = DigestType.CRC32; - private static final String PASSWORD = "testPasswd"; - private static final int printprogress = 5; - - public UpdateLedgerOpTest() { - super(3); - useUUIDasBookieId = false; - baseConf.setGcWaitTime(100000); - } - - UpdateLedgerNotifier progressable = new UpdateLedgerNotifier() { - long lastReport = System.nanoTime(); - - @Override - public void progress(long updated, long issued) { - if (TimeUnit.MILLISECONDS.toSeconds(MathUtils.elapsedMSec(lastReport)) >= printprogress) { - LOG.info("Number of ledgers issued={}, updated={}", issued, updated); - lastReport = MathUtils.nowInNano(); - } - } - }; - - /** - * Tests verifies update bookie id to FQDN hostname when there are many ledgers. - */ - @Test - public void testManyLedgersWithFQDNHostname() throws Exception { - testManyLedgers(false); - } - - /** - * Tests verifies update bookie id to short hostname when there are many ledgers. - */ - @Test(timeout = 120000) - public void testManyLedgersWithShortHostname() throws Exception { - testManyLedgers(true); - } - - public void testManyLedgers(boolean useShortHostName) throws Exception { - try (BookKeeper bk = new BookKeeper(baseClientConf, zkc); - BookKeeperAdmin bkadmin = new BookKeeperAdmin(bk, baseClientConf)) { - - LOG.info("Create ledger and add entries to it"); - List ledgers = new ArrayList(); - LedgerHandle lh1 = createLedgerWithEntries(bk, 0); - ledgers.add(lh1); - for (int i = 0; i < 99; i++) { - ledgers.add(createLedgerWithEntries(bk, 0)); - } - - List ensemble = lh1.getLedgerMetadata().getEnsembleAt(0); - - BookieSocketAddress curBookieAddr = bk.getBookieAddressResolver().resolve(ensemble.get(0)); - baseConf.setUseHostNameAsBookieID(true); - baseConf.setUseShortHostName(useShortHostName); - BookieSocketAddress curBookieId = BookieImpl.getBookieAddress(baseConf); - BookieId toBookieAddr = new BookieSocketAddress(curBookieId.getHostName() + ":" - + curBookieAddr.getPort()).toBookieId(); - UpdateLedgerOp updateLedgerOp = new UpdateLedgerOp(bk, bkadmin); - updateLedgerOp.updateBookieIdInLedgers(curBookieAddr.toBookieId(), toBookieAddr, - 5, 25, Integer.MIN_VALUE, progressable); - - for (LedgerHandle lh : ledgers) { - lh.close(); - LedgerHandle openLedger = bk.openLedger(lh.getId(), digestType, PASSWORD.getBytes()); - ensemble = openLedger.getLedgerMetadata().getEnsembleAt(0); - assertTrue("Failed to update the ledger metadata to use bookie host name", - ensemble.contains(toBookieAddr)); - assertFalse("Failed to update the ledger metadata to use bookie host name", - ensemble.contains(curBookieAddr.toBookieId())); - } - } - } - - /** - * Tests verifies with limit value lesser than the total number of ledgers. - */ - @Test - public void testLimitLessThanTotalLedgers() throws Exception { - try (BookKeeper bk = new BookKeeper(baseClientConf, zkc); - BookKeeperAdmin bkadmin = new BookKeeperAdmin(bk, baseClientConf)) { - - LOG.info("Create ledger and add entries to it"); - List ledgers = new ArrayList(); - LedgerHandle lh1 = createLedgerWithEntries(bk, 0); - ledgers.add(lh1); - for (int i = 1; i < 10; i++) { - ledgers.add(createLedgerWithEntries(bk, 0)); - } - - List ensemble = lh1.getLedgerMetadata().getEnsembleAt(0); - - BookieId curBookieAddr = ensemble.get(0); - baseConf.setUseHostNameAsBookieID(true); - - BookieSocketAddress toBookieId = BookieImpl.getBookieAddress(baseConf); - BookieId toBookieAddr = new BookieSocketAddress(toBookieId.getHostName() + ":" - + bk.getBookieAddressResolver().resolve(curBookieAddr).getPort()).toBookieId(); - UpdateLedgerOp updateLedgerOp = new UpdateLedgerOp(bk, bkadmin); - updateLedgerOp.updateBookieIdInLedgers(curBookieAddr, toBookieAddr, 7, 35, 4, progressable); - int updatedLedgersCount = getUpdatedLedgersCount(bk, ledgers, toBookieAddr); - assertEquals("Failed to update the ledger metadata to use bookie host name", 4, updatedLedgersCount); - - // next execution - updateLedgerOp.updateBookieIdInLedgers(curBookieAddr, toBookieAddr, 2, 10, 10, progressable); - updatedLedgersCount = getUpdatedLedgersCount(bk, ledgers, toBookieAddr); - assertEquals("Failed to update the ledger metadata to use bookie host name", 10, updatedLedgersCount); - - // no ledgers - updateLedgerOp.updateBookieIdInLedgers(curBookieAddr, toBookieAddr, 3, 15, 20, progressable); - updatedLedgersCount = getUpdatedLedgersCount(bk, ledgers, toBookieAddr); - assertEquals("Failed to update the ledger metadata to use bookie host name", 10, updatedLedgersCount); - - // no ledgers - updateLedgerOp.updateBookieIdInLedgers(curBookieAddr, toBookieAddr, 3, 15, Integer.MIN_VALUE, progressable); - updatedLedgersCount = getUpdatedLedgersCount(bk, ledgers, toBookieAddr); - assertEquals("Failed to update the ledger metadata to use bookie host name", 10, updatedLedgersCount); - } - } - - /** - * Tests verifies the ensemble reformation after updating the bookie id to - * FQDN hostname in the existing ensemble. - */ - @Test - public void testChangeEnsembleAfterRenamingToFQDNHostname() throws Exception { - testChangeEnsembleAfterRenaming(false); - } - - /** - * Tests verifies the ensemble reformation after updating the bookie id to - * short hostname in the existing ensemble. - */ - @Test(timeout = 120000) - public void testChangeEnsembleAfterRenamingToShortHostname() throws Exception { - testChangeEnsembleAfterRenaming(true); - } - - public void testChangeEnsembleAfterRenaming(boolean useShortHostName) throws Exception { - - try (BookKeeper bk = new BookKeeper(baseClientConf, zkc); - BookKeeperAdmin bkadmin = new BookKeeperAdmin(bk, baseClientConf)) { - - LOG.info("Create ledger and add entries to it"); - LedgerHandle lh = createLedgerWithEntries(bk, 100); - - BookieServer bookieServer = serverByIndex(0); - List ensemble = lh.getLedgerMetadata().getEnsembleAt(0); - BookieSocketAddress curBookieAddr = null; - for (BookieId bookieSocketAddress : ensemble) { - BookieSocketAddress resolved = bk.getBookieAddressResolver().resolve(bookieSocketAddress); - if (bookieServer.getLocalAddress().equals(resolved)) { - curBookieAddr = resolved; - } - } - assertNotNull("Couldn't find the bookie in ledger metadata!", curBookieAddr); - baseConf.setUseHostNameAsBookieID(true); - baseConf.setUseShortHostName(useShortHostName); - BookieSocketAddress toBookieId = BookieImpl.getBookieAddress(baseConf); - BookieId toBookieAddr = new BookieSocketAddress(toBookieId.getHostName() + ":" - + curBookieAddr.getPort()).toBookieId(); - UpdateLedgerOp updateLedgerOp = new UpdateLedgerOp(bk, bkadmin); - updateLedgerOp.updateBookieIdInLedgers(curBookieAddr.toBookieId(), toBookieAddr, 5, 25, 100, progressable); - - bookieServer.shutdown(); - - ServerConfiguration serverConf1 = newServerConfiguration(); - startAndAddBookie(serverConf1); - - final CountDownLatch latch = new CountDownLatch(1); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - lh.asyncAddEntry("foobar".getBytes(), new AddCallback() { - @Override - public void addComplete(int rccb, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - latch.countDown(); - } - }, null); - if (!latch.await(30, TimeUnit.SECONDS)) { - throw new Exception("Entries took too long to add"); - } - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - lh.close(); - LedgerHandle openLedger = bk.openLedger(lh.getId(), digestType, PASSWORD.getBytes()); - final LedgerMetadata ledgerMetadata = openLedger.getLedgerMetadata(); - assertEquals("Failed to reform ensemble!", 2, ledgerMetadata.getAllEnsembles().size()); - ensemble = ledgerMetadata.getEnsembleAt(0); - assertTrue("Failed to update the ledger metadata to use bookie host name", - ensemble.contains(toBookieAddr)); - } - } - - /** - * Tests verifies simultaneous flow between adding entries and rename of - * bookie id. - */ - @Test - public void testRenameWhenAddEntryInProgress() throws Exception { - try (final BookKeeper bk = new BookKeeper(baseClientConf, zkc); - BookKeeperAdmin bkadmin = new BookKeeperAdmin(bk, baseClientConf)) { - - LOG.info("Create ledger and add entries to it"); - final int numOfEntries = 5000; - final CountDownLatch latch = new CountDownLatch(numOfEntries); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - final LedgerHandle lh = createLedgerWithEntries(bk, 1); - latch.countDown(); - Thread th = new Thread() { - public void run() { - final AddCallback cb = new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - if (entryId % 100 == 0) { - LOG.info("Added entries till entryId:{}", entryId); - } - latch.countDown(); - } - }; - for (int i = 1; i < numOfEntries; i++) { - lh.asyncAddEntry(("foobar" + i).getBytes(), cb, null); - } - - } - }; - th.start(); - List ensemble = lh.getLedgerMetadata().getEnsembleAt(0); - BookieSocketAddress curBookieAddr = bk.getBookieAddressResolver().resolve(ensemble.get(0)); - BookieId toBookieAddr = BookieId.parse("localhost:" + curBookieAddr.getPort()); - UpdateLedgerOp updateLedgerOp = new UpdateLedgerOp(bk, bkadmin); - updateLedgerOp.updateBookieIdInLedgers(curBookieAddr.toBookieId(), toBookieAddr, 5, 25, 100, progressable); - - if (!latch.await(120, TimeUnit.SECONDS)) { - throw new Exception("Entries took too long to add"); - } - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - lh.close(); - LedgerHandle openLedger = bk.openLedger(lh.getId(), digestType, PASSWORD.getBytes()); - ensemble = openLedger.getLedgerMetadata().getEnsembleAt(0); - assertTrue("Failed to update the ledger metadata to use bookie host name", - ensemble.contains(toBookieAddr)); - } - } - - private int getUpdatedLedgersCount(BookKeeper bk, List ledgers, BookieId toBookieAddr) - throws InterruptedException, BKException { - List ensemble; - int updatedLedgersCount = 0; - for (LedgerHandle lh : ledgers) { - lh.close(); - LedgerHandle openLedger = bk.openLedger(lh.getId(), digestType, PASSWORD.getBytes()); - ensemble = openLedger.getLedgerMetadata().getEnsembleAt(0); - if (ensemble.contains(toBookieAddr)) { - updatedLedgersCount++; - } - } - return updatedLedgersCount; - } - - private LedgerHandle createLedgerWithEntries(BookKeeper bk, int numOfEntries) throws Exception { - LedgerHandle lh = bk.createLedger(3, 3, digestType, PASSWORD.getBytes()); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - final CountDownLatch latch = new CountDownLatch(numOfEntries); - - final AddCallback cb = new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - latch.countDown(); - } - }; - for (int i = 0; i < numOfEntries; i++) { - lh.asyncAddEntry(("foobar" + i).getBytes(), cb, null); - } - if (!latch.await(30, TimeUnit.SECONDS)) { - throw new Exception("Entries took too long to add"); - } - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - return lh; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BKExceptionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BKExceptionTest.java deleted file mode 100644 index 25f1d8f65c8..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BKExceptionTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2017 The Apache Software Foundation. - * - * Licensed 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. - */ -package org.apache.bookkeeper.client.api; - -import static org.apache.bookkeeper.client.api.BKException.Code.UnexpectedConditionException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; - -import java.lang.reflect.Field; -import org.junit.Test; - -/** - * Tests for BKException methods. - */ -public class BKExceptionTest { - - @Test - public void testGetMessage() throws Exception { - Field[] fields = BKException.Code.class.getFields(); - int count = 0; - for (Field f : fields) { - if (f.getType() == Integer.TYPE && !f.getName().equals("UNINITIALIZED")) { - int code = f.getInt(null); - String msg = BKException.getMessage(code); - if (code == UnexpectedConditionException) { - assertEquals("Unexpected condition", msg); - } else { - assertNotEquals("failure on code " + f.getName(), "Unexpected condition", msg); - } - count++; - } - } - // assert that we found at least 1 code other than UnexpectedConditionException - assertTrue(count > 2); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperApiTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperApiTest.java deleted file mode 100644 index 5cd71247a9d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperApiTest.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client.api; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasProperty; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.Unpooled; -import java.nio.ByteBuffer; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.BKDigestMatchException; -import org.apache.bookkeeper.client.BKException.BKDuplicateEntryIdException; -import org.apache.bookkeeper.client.BKException.BKLedgerFencedException; -import org.apache.bookkeeper.client.BKException.BKNoSuchLedgerExistsOnMetadataServerException; -import org.apache.bookkeeper.client.BKException.BKUnauthorizedAccessException; -import org.apache.bookkeeper.client.MockBookKeeperTestCase; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.util.LoggerOutput; -import org.junit.Rule; -import org.junit.Test; -import org.slf4j.event.LoggingEvent; - -/** - * Unit tests of classes in this package. - */ -public class BookKeeperApiTest extends MockBookKeeperTestCase { - - private static final byte[] bigData = new byte[1024]; - private static final byte[] data = "foo".getBytes(UTF_8); - private static final byte[] password = "password".getBytes(UTF_8); - - @Rule - public LoggerOutput loggerOutput = new LoggerOutput(); - - @Test - public void testWriteHandle() throws Exception { - try (WriteHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .execute())) { - - // test writer is able to write - writer.append(ByteBuffer.wrap(data)); - assertEquals(0L, writer.getLastAddPushed()); - writer.append(Unpooled.wrappedBuffer(data)); - assertEquals(1L, writer.getLastAddPushed()); - long expectedEntryId = writer.append(ByteBuffer.wrap(data)); - assertEquals(expectedEntryId, writer.getLastAddConfirmed()); - assertEquals(3 * data.length, writer.getLength()); - } - } - - @Test - public void testWriteAdvHandle() throws Exception { - long ledgerId = 12345; - setNewGeneratedLedgerId(ledgerId); - try (WriteAdvHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .makeAdv() - .execute())) { - assertEquals(ledgerId, writer.getId()); - - // test writer is able to write - long entryId = 0; - writer.write(entryId++, ByteBuffer.wrap(data)); - writer.write(entryId++, Unpooled.wrappedBuffer(data)); - long expectedEntryId = writer.write(entryId++, ByteBuffer.wrap(data)); - assertEquals(expectedEntryId, writer.getLastAddConfirmed()); - assertEquals(3 * data.length, writer.getLength()); - } - } - - @Test - public void testWriteAdvHandleWithFixedLedgerId() throws Exception { - setNewGeneratedLedgerId(12345); - try (WriteAdvHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .makeAdv() - .withLedgerId(1234) - .execute())) { - assertEquals(1234, writer.getId()); - - // test writer is able to write - long entryId = 0; - writer.write(entryId++, ByteBuffer.wrap(data)); - writer.write(entryId++, Unpooled.wrappedBuffer(data)); - long expectedEntryId = writer.write(entryId++, ByteBuffer.wrap(data)); - assertEquals(expectedEntryId, writer.getLastAddConfirmed()); - assertEquals(3 * data.length, writer.getLength()); - } - } - - @Test(expected = BKDuplicateEntryIdException.class) - public void testWriteAdvHandleBKDuplicateEntryId() throws Exception { - try (WriteAdvHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .makeAdv() - .withLedgerId(1234) - .execute())) { - assertEquals(1234, writer.getId()); - long entryId = 0; - writer.write(entryId++, ByteBuffer.wrap(data)); - assertEquals(data.length, writer.getLength()); - writer.write(entryId - 1, ByteBuffer.wrap(data)); - } - } - - @Test(expected = BKUnauthorizedAccessException.class) - public void testOpenLedgerUnauthorized() throws Exception { - long lId; - try (WriteHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .execute())) { - lId = writer.getId(); - assertEquals(-1L, writer.getLastAddPushed()); - } - try (ReadHandle ignored = result(newOpenLedgerOp() - .withPassword("bad-password".getBytes(UTF_8)) - .withLedgerId(lId) - .execute())) { - } - } - - /** - * Verify the functionality Ledgers with different digests. - * - * @throws Exception - */ - @Test - public void testLedgerDigests() throws Exception { - for (DigestType type: DigestType.values()) { - long lId; - try (WriteHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withDigestType(type) - .withPassword(password) - .execute())) { - lId = writer.getId(); - assertEquals(-1L, writer.getLastAddPushed()); - writer.append(ByteBuffer.wrap(bigData)); - assertEquals(bigData.length, writer.getLength()); - } - try (ReadHandle reader = result(newOpenLedgerOp() - .withDigestType(type) - .withPassword(password) - .withLedgerId(lId) - .execute())) { - LedgerEntries entries = reader.read(0, 0); - checkEntries(entries, bigData); - } - result(newDeleteLedgerOp().withLedgerId(lId).execute()); - } - } - - - @Test - public void testOpenLedgerDigestUnmatchedWhenAutoDetectionEnabled() throws Exception { - testOpenLedgerDigestUnmatched(true); - } - - @Test - public void testOpenLedgerDigestUnmatchedWhenAutoDetectionDisabled() throws Exception { - testOpenLedgerDigestUnmatched(false); - } - - private void testOpenLedgerDigestUnmatched(boolean autodetection) throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setEnableDigestTypeAutodetection(autodetection); - setBookKeeperConfig(conf); - - long lId; - try (WriteHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withDigestType(DigestType.MAC) - .withPassword(password) - .execute())) { - lId = writer.getId(); - assertEquals(-1L, writer.getLastAddPushed()); - } - try (ReadHandle ignored = result(newOpenLedgerOp() - .withDigestType(DigestType.CRC32) - .withPassword(password) - .withLedgerId(lId) - .execute())) { - if (!autodetection) { - fail("Should fail to open read handle if digest type auto detection is disabled."); - } - } catch (BKDigestMatchException bme) { - if (autodetection) { - fail("Should not fail to open read handle if digest type auto detection is enabled."); - } - } - } - - @Test - public void testOpenLedgerNoSealed() throws Exception { - try (WriteHandle writer = result(newCreateLedgerOp() - .withEnsembleSize(3) - .withWriteQuorumSize(3) - .withAckQuorumSize(2) - .withPassword(password) - .execute())) { - long lId = writer.getId(); - // write data and populate LastAddConfirmed - writer.append(ByteBuffer.wrap(data)); - writer.append(ByteBuffer.wrap(data)); - - try (ReadHandle reader = result(newOpenLedgerOp() - .withPassword(password) - .withRecovery(false) - .withLedgerId(lId) - .execute())) { - assertFalse(reader.isClosed()); - } - } - } - - @Test - public void testOpenLedgerRead() throws Exception { - long lId; - try (WriteHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .execute())) { - lId = writer.getId(); - // write data and populate LastAddConfirmed - writer.append(ByteBuffer.wrap(data)); - writer.append(ByteBuffer.wrap(data)); - writer.append(ByteBuffer.wrap(data)); - } - - try (ReadHandle reader = result(newOpenLedgerOp() - .withPassword(password) - .withRecovery(false) - .withLedgerId(lId) - .execute())) { - assertTrue(reader.isClosed()); - assertEquals(2, reader.getLastAddConfirmed()); - assertEquals(3 * data.length, reader.getLength()); - assertEquals(2, reader.readLastAddConfirmed()); - assertEquals(2, reader.tryReadLastAddConfirmed()); - checkEntries(reader.read(0, reader.getLastAddConfirmed()), data); - checkEntries(reader.readUnconfirmed(0, reader.getLastAddConfirmed()), data); - - // test readLastAddConfirmedAndEntry - LastConfirmedAndEntry lastConfirmedAndEntry = - reader.readLastAddConfirmedAndEntry(0, 999, false); - assertEquals(2L, lastConfirmedAndEntry.getLastAddConfirmed()); - assertArrayEquals(data, lastConfirmedAndEntry.getEntry().getEntryBytes()); - lastConfirmedAndEntry.close(); - } - } - - @Test(expected = BKLedgerFencedException.class) - public void testOpenLedgerWithRecovery() throws Exception { - - loggerOutput.expect((List logEvents) -> { - assertThat(logEvents, hasItem(hasProperty("message", - containsString("due to LedgerFencedException: " - + "Ledger has been fenced off. Some other client must have opened it to read") - ))); - }); - - long lId; - try (WriteHandle writer = result(newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .execute())) { - lId = writer.getId(); - - writer.append(ByteBuffer.wrap(data)); - writer.append(ByteBuffer.wrap(data)); - assertEquals(1L, writer.getLastAddPushed()); - - // open with fencing - try (ReadHandle reader = result(newOpenLedgerOp() - .withPassword(password) - .withRecovery(true) - .withLedgerId(lId) - .execute())) { - assertTrue(reader.isClosed()); - assertEquals(1L, reader.getLastAddConfirmed()); - } - - writer.append(ByteBuffer.wrap(data)); - - } - } - - @Test(expected = BKNoSuchLedgerExistsOnMetadataServerException.class) - public void testDeleteLedger() throws Exception { - long lId; - - try (WriteHandle writer = result(newCreateLedgerOp() - .withPassword(password) - .execute())) { - lId = writer.getId(); - assertEquals(-1L, writer.getLastAddPushed()); - } - - result(newDeleteLedgerOp().withLedgerId(lId).execute()); - - result(newOpenLedgerOp() - .withPassword(password) - .withLedgerId(lId) - .execute()); - } - - @Test(expected = BKNoSuchLedgerExistsOnMetadataServerException.class) - public void testCannotDeleteLedgerTwice() throws Exception { - long lId; - - try (WriteHandle writer = result(newCreateLedgerOp() - .withPassword(password) - .execute())) { - lId = writer.getId(); - assertEquals(-1L, writer.getLastAddPushed()); - } - result(newDeleteLedgerOp().withLedgerId(lId).execute()); - result(newDeleteLedgerOp().withLedgerId(lId).execute()); - } - - @Test - public void testLedgerEntriesIterable() throws Exception { - long lId; - try (WriteHandle writer = newCreateLedgerOp() - .withAckQuorumSize(1) - .withWriteQuorumSize(2) - .withEnsembleSize(3) - .withPassword(password) - .execute().get()) { - lId = writer.getId(); - // write data and populate LastAddConfirmed - writer.append(ByteBuffer.wrap(data)); - writer.append(ByteBuffer.wrap(data)); - writer.append(ByteBuffer.wrap(data)); - } - - try (ReadHandle reader = newOpenLedgerOp() - .withPassword(password) - .withRecovery(false) - .withLedgerId(lId) - .execute().get()) { - long lac = reader.getLastAddConfirmed(); - assertEquals(2, lac); - - try (LedgerEntries entries = reader.read(0, lac)) { - AtomicLong i = new AtomicLong(0); - for (LedgerEntry e : entries) { - assertEquals(i.getAndIncrement(), e.getEntryId()); - assertArrayEquals(data, e.getEntryBytes()); - } - i.set(0); - entries.forEach((e) -> { - assertEquals(i.getAndIncrement(), e.getEntryId()); - assertArrayEquals(data, e.getEntryBytes()); - }); - } - } - } - - @Test - public void testBKExceptionCodeLogger() { - assertEquals("OK: No problem", BKException.codeLogger(0).toString()); - assertEquals("ReadException: Error while reading ledger", BKException.codeLogger(-1).toString()); - assertEquals("IncorrectParameterException: Incorrect parameter input", BKException.codeLogger(-14).toString()); - assertEquals("LedgerFencedException: Ledger has been fenced off. Some other client must have opened it to read", - BKException.codeLogger(-101).toString()); - assertEquals("ReplicationException: Errors in replication pipeline", BKException.codeLogger(-200).toString()); - - assertEquals("UnexpectedConditionException: Unexpected condition", BKException.codeLogger(-999).toString()); - - assertEquals("1: Unexpected condition", BKException.codeLogger(1).toString()); - assertEquals("123: Unexpected condition", BKException.codeLogger(123).toString()); - assertEquals("-201: Unexpected condition", BKException.codeLogger(-201).toString()); - } - - private static void checkEntries(LedgerEntries entries, byte[] data) - throws InterruptedException, BKException { - Iterator iterator = entries.iterator(); - while (iterator.hasNext()) { - LedgerEntry entry = iterator.next(); - assertArrayEquals(data, entry.getEntryBytes()); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersOpenLedgerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersOpenLedgerTest.java deleted file mode 100644 index 00e14fe2c12..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersOpenLedgerTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client.api; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyLong; -import static org.mockito.Mockito.doAnswer; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.MockBookKeeperTestCase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -/** - * Tests for BookKeeper open ledger operations. - */ -@RunWith(Parameterized.class) -public class BookKeeperBuildersOpenLedgerTest extends MockBookKeeperTestCase { - - private static final int ensembleSize = 3; - private static final int writeQuorumSize = 2; - private static final int ackQuorumSize = 1; - private static final long ledgerId = 12342L; - private static final Map customMetadata = new HashMap<>(); - private static final byte[] password = new byte[3]; - private static final byte[] entryData = new byte[32]; - - private boolean withRecovery; - - public BookKeeperBuildersOpenLedgerTest(boolean withRecovery) { - this.withRecovery = withRecovery; - } - - @Parameterized.Parameters(name = "withRecovery:({0})") - public static Collection data() { - return Arrays.asList(new Object[][]{ - {true}, - {false} - }); - } - - @Test - public void testOpenLedger() throws Exception { - LedgerMetadata ledgerMetadata = generateLedgerMetadata(ensembleSize, - writeQuorumSize, ackQuorumSize, password, customMetadata); - registerMockLedgerMetadata(ledgerId, ledgerMetadata); - - ledgerMetadata.getAllEnsembles().values().forEach(bookieAddressList -> { - bookieAddressList.forEach(bookieAddress -> { - registerMockEntryForRead(ledgerId, BookieProtocol.LAST_ADD_CONFIRMED, bookieAddress, entryData, -1); - registerMockEntryForRead(ledgerId, 0, bookieAddress, entryData, -1); - }); - }); - - result(newOpenLedgerOp() - .withPassword(ledgerMetadata.getPassword()) - .withDigestType(DigestType.CRC32) - .withLedgerId(ledgerId) - .withRecovery(withRecovery) - .execute()); - } - - @Test - public void testOpenLedgerWithTimeoutEx() throws Exception { - mockReadEntryTimeout(); - LedgerMetadata ledgerMetadata = generateLedgerMetadata(ensembleSize, - writeQuorumSize, ackQuorumSize, password, customMetadata); - registerMockLedgerMetadata(ledgerId, ledgerMetadata); - ledgerMetadata.getAllEnsembles().values().forEach(bookieAddressList -> { - bookieAddressList.forEach(bookieAddress -> { - registerMockEntryForRead(ledgerId, BookieProtocol.LAST_ADD_CONFIRMED, bookieAddress, entryData, -1); - registerMockEntryForRead(ledgerId, 0, bookieAddress, entryData, -1); - }); - }); - try { - result(newOpenLedgerOp() - .withPassword(ledgerMetadata.getPassword()) - .withDigestType(DigestType.CRC32) - .withLedgerId(ledgerId) - .withRecovery(withRecovery) - .execute()); - fail("Expect timeout error"); - } catch (BKException.BKTimeoutException timeoutException) { - // Expect timeout error. - } - // Reset bk client. - resetBKClient(); - } - - protected LedgerMetadata generateLedgerMetadata(int ensembleSize, - int writeQuorumSize, int ackQuorumSize, byte[] password, - Map customMetadata) throws BKException.BKNotEnoughBookiesException { - return LedgerMetadataBuilder.create() - .withId(12L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .withPassword(password) - .withDigestType(BookKeeper.DigestType.CRC32.toApiDigestType()) - .withCustomMetadata(customMetadata) - .withCreationTime(System.currentTimeMillis()) - .newEnsembleEntry(0, generateNewEnsemble(ensembleSize)).build(); - } - - private void mockReadEntryTimeout() { - // Mock read entry. - doAnswer(invocation -> { - long ledgerId = (long) invocation.getArguments()[1]; - long entryId = (long) invocation.getArguments()[2]; - - BookkeeperInternalCallbacks.ReadEntryCallback callback = - (BookkeeperInternalCallbacks.ReadEntryCallback) invocation.getArguments()[3]; - Object ctx = invocation.getArguments()[4]; - callback.readEntryComplete(BKException.Code.TimeoutException, ledgerId, entryId, null, ctx); - return null; - }).when(bookieClient).readEntry(any(BookieId.class), - anyLong(), anyLong(), any(BookkeeperInternalCallbacks.ReadEntryCallback.class), - any(), anyInt(), any()); - // Mock read lac. - doAnswer(invocation -> { - long ledgerId = (long) invocation.getArguments()[1]; - BookkeeperInternalCallbacks.ReadLacCallback callback = - (BookkeeperInternalCallbacks.ReadLacCallback) invocation.getArguments()[2]; - Object ctx = invocation.getArguments()[3]; - callback.readLacComplete(BKException.Code.TimeoutException, ledgerId, null, null, ctx); - return null; - }).when(bookieClient).readLac(any(BookieId.class), - anyLong(), any(BookkeeperInternalCallbacks.ReadLacCallback.class), - any()); - } - - private void resetBKClient() throws Exception { - tearDown(); - setup(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersTest.java deleted file mode 100644 index 478a3ef208f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersTest.java +++ /dev/null @@ -1,427 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client.api; - -import static org.apache.bookkeeper.client.api.WriteFlag.DEFERRED_SYNC; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.BKClientClosedException; -import org.apache.bookkeeper.client.BKException.BKIncorrectParameterException; -import org.apache.bookkeeper.client.BKException.BKNoSuchLedgerExistsOnMetadataServerException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.MockBookKeeperTestCase; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.junit.Test; - -/** - * Unit tests of builders. - */ -public class BookKeeperBuildersTest extends MockBookKeeperTestCase { - - private static final int ensembleSize = 3; - private static final int writeQuorumSize = 2; - private static final int ackQuorumSize = 1; - private static final long ledgerId = 12342L; - private static final Map customMetadata = new HashMap<>(); - private static final byte[] password = new byte[3]; - private static final byte[] entryData = new byte[32]; - private static final EnumSet writeFlagsDeferredSync = EnumSet.of(DEFERRED_SYNC); - - @Test - public void testCreateLedger() throws Exception { - setNewGeneratedLedgerId(ledgerId); - WriteHandle writer = newCreateLedgerOp() - .withAckQuorumSize(ackQuorumSize) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withCustomMetadata(customMetadata) - .withPassword(password) - .execute() - .get(); - assertEquals(ledgerId, writer.getId()); - LedgerMetadata metadata = getLedgerMetadata(ledgerId); - assertEquals(ensembleSize, metadata.getEnsembleSize()); - assertEquals(ackQuorumSize, metadata.getAckQuorumSize()); - assertEquals(writeQuorumSize, metadata.getWriteQuorumSize()); - assertArrayEquals(password, metadata.getPassword()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailEnsembleSize0() throws Exception { - result(newCreateLedgerOp() - .withEnsembleSize(0) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailWriteQuorumSize0() throws Exception { - result(newCreateLedgerOp() - .withEnsembleSize(2) - .withWriteQuorumSize(0) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailNullWriteFlags() throws Exception { - result(newCreateLedgerOp() - .withWriteFlags((EnumSet) null) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailAckQuorumSize0() throws Exception { - result(newCreateLedgerOp() - .withEnsembleSize(2) - .withWriteQuorumSize(1) - .withAckQuorumSize(0) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailWriteQuorumSizeGreaterThanEnsembleSize() throws Exception { - result(newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(2) - .withAckQuorumSize(1) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailAckQuorumSizeGreaterThanWriteQuorumSize() throws Exception { - result(newCreateLedgerOp() - .withEnsembleSize(1) - .withWriteQuorumSize(1) - .withAckQuorumSize(2) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailNoPassword() throws Exception { - result(newCreateLedgerOp() - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailPasswordNull() throws Exception { - result(newCreateLedgerOp() - .withPassword(null) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailCustomMetadataNull() throws Exception { - result(newCreateLedgerOp() - .withCustomMetadata(null) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailDigestTypeNullAndAutodetectionTrue() throws Exception { - ClientConfiguration config = new ClientConfiguration(); - config.setEnableDigestTypeAutodetection(true); - setBookKeeperConfig(config); - result(newCreateLedgerOp() - .withDigestType(null) - .withPassword(password) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailDigestTypeNullAndAutodetectionFalse() throws Exception { - ClientConfiguration config = new ClientConfiguration(); - config.setEnableDigestTypeAutodetection(false); - setBookKeeperConfig(config); - result(newCreateLedgerOp() - .withDigestType(null) - .withPassword(password) - .execute()); - fail("shoud not be able to create a ledger with such specs"); - } - - @Test(expected = BKClientClosedException.class) - public void testFailDigestTypeNullAndBookkKeeperClosed() throws Exception { - closeBookkeeper(); - result(newCreateLedgerOp() - .withPassword(password) - .execute()); - fail("shoud not be able to create a ledger, client is closed"); - } - - @Test - public void testCreateAdvLedger() throws Exception { - setNewGeneratedLedgerId(ledgerId); - WriteAdvHandle writer = newCreateLedgerOp() - .withAckQuorumSize(ackQuorumSize) - .withEnsembleSize(ensembleSize) - .withPassword(password) - .withWriteQuorumSize(writeQuorumSize) - .withCustomMetadata(customMetadata) - .makeAdv() - .execute() - .get(); - assertEquals(ledgerId, writer.getId()); - LedgerMetadata metadata = getLedgerMetadata(ledgerId); - assertEquals(ensembleSize, metadata.getEnsembleSize()); - assertEquals(ackQuorumSize, metadata.getAckQuorumSize()); - assertEquals(writeQuorumSize, metadata.getWriteQuorumSize()); - assertArrayEquals(password, metadata.getPassword()); - } - - @Test - public void testDefaultWriteFlagsEmpty() throws Exception { - setNewGeneratedLedgerId(ledgerId); - WriteHandle writer = newCreateLedgerOp() - .withAckQuorumSize(ackQuorumSize) - .withEnsembleSize(ensembleSize) - .withPassword(password) - .withWriteQuorumSize(writeQuorumSize) - .withCustomMetadata(customMetadata) - .execute() - .get(); - assertEquals(ledgerId, writer.getId()); - LedgerMetadata metadata = getLedgerMetadata(ledgerId); - assertEquals(ensembleSize, metadata.getEnsembleSize()); - assertEquals(ackQuorumSize, metadata.getAckQuorumSize()); - assertEquals(writeQuorumSize, metadata.getWriteQuorumSize()); - assertArrayEquals(password, metadata.getPassword()); - LedgerHandle lh = (LedgerHandle) writer; - assertEquals(WriteFlag.NONE, lh.getWriteFlags()); - } - - @Test - public void testCreateAdvLedgerWriteFlags() throws Exception { - setNewGeneratedLedgerId(ledgerId); - WriteAdvHandle writer = newCreateLedgerOp() - .withWriteFlags(writeFlagsDeferredSync) - .withAckQuorumSize(ackQuorumSize) - .withEnsembleSize(ensembleSize) - .withPassword(password) - .withWriteQuorumSize(writeQuorumSize) - .withCustomMetadata(customMetadata) - .makeAdv() - .execute() - .get(); - assertEquals(ledgerId, writer.getId()); - LedgerMetadata metadata = getLedgerMetadata(ledgerId); - assertEquals(ensembleSize, metadata.getEnsembleSize()); - assertEquals(ackQuorumSize, metadata.getAckQuorumSize()); - assertEquals(writeQuorumSize, metadata.getWriteQuorumSize()); - assertArrayEquals(password, metadata.getPassword()); - LedgerHandle lh = (LedgerHandle) writer; - assertEquals(writeFlagsDeferredSync, lh.getWriteFlags()); - } - - @Test - public void testCreateLedgerWriteFlags() throws Exception { - setNewGeneratedLedgerId(ledgerId); - WriteHandle writer = newCreateLedgerOp() - .withWriteFlags(writeFlagsDeferredSync) - .withAckQuorumSize(ackQuorumSize) - .withEnsembleSize(ensembleSize) - .withPassword(password) - .withWriteQuorumSize(writeQuorumSize) - .withCustomMetadata(customMetadata) - .execute() - .get(); - assertEquals(ledgerId, writer.getId()); - LedgerMetadata metadata = getLedgerMetadata(ledgerId); - assertEquals(ensembleSize, metadata.getEnsembleSize()); - assertEquals(ackQuorumSize, metadata.getAckQuorumSize()); - assertEquals(writeQuorumSize, metadata.getWriteQuorumSize()); - assertArrayEquals(password, metadata.getPassword()); - LedgerHandle lh = (LedgerHandle) writer; - assertEquals(writeFlagsDeferredSync, lh.getWriteFlags()); - } - - @Test - public void testCreateLedgerWriteFlagsVarargs() throws Exception { - setNewGeneratedLedgerId(ledgerId); - WriteHandle writer = newCreateLedgerOp() - .withWriteFlags(DEFERRED_SYNC) - .withAckQuorumSize(ackQuorumSize) - .withEnsembleSize(ensembleSize) - .withPassword(password) - .withWriteQuorumSize(writeQuorumSize) - .withCustomMetadata(customMetadata) - .execute() - .get(); - assertEquals(ledgerId, writer.getId()); - LedgerMetadata metadata = getLedgerMetadata(ledgerId); - assertEquals(ensembleSize, metadata.getEnsembleSize()); - assertEquals(ackQuorumSize, metadata.getAckQuorumSize()); - assertEquals(writeQuorumSize, metadata.getWriteQuorumSize()); - assertArrayEquals(password, metadata.getPassword()); - LedgerHandle lh = (LedgerHandle) writer; - assertEquals(writeFlagsDeferredSync, lh.getWriteFlags()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailCreateAdvLedgerBadFixedLedgerIdMinus1() throws Exception { - result(newCreateLedgerOp() - .withPassword(password) - .makeAdv() - .withLedgerId(-1) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testFailCreateAdvLedgerBadFixedLedgerIdNegative() throws Exception { - result(newCreateLedgerOp() - .withPassword(password) - .makeAdv() - .withLedgerId(-2) - .execute()); - fail("shoud not be able to create a ledger with such specs"); - } - - @Test(expected = BKNoSuchLedgerExistsOnMetadataServerException.class) - public void testOpenLedgerNoId() throws Exception { - result(newOpenLedgerOp().execute()); - } - - @Test(expected = BKNoSuchLedgerExistsOnMetadataServerException.class) - public void testOpenLedgerBadId() throws Exception { - result(newOpenLedgerOp() - .withPassword(password) - .withLedgerId(ledgerId) - .execute()); - } - - @Test(expected = BKClientClosedException.class) - public void testOpenLedgerClientClosed() throws Exception { - closeBookkeeper(); - result(newOpenLedgerOp() - .withPassword(password) - .withLedgerId(ledgerId) - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testDeleteLedgerNoLedgerId() throws Exception { - result(newDeleteLedgerOp() - .execute()); - } - - @Test(expected = BKIncorrectParameterException.class) - public void testDeleteLedgerBadLedgerId() throws Exception { - result(newDeleteLedgerOp() - .withLedgerId(-1) - .execute()); - } - - @Test - public void testDeleteLedger() throws Exception { - LedgerMetadata ledgerMetadata = generateLedgerMetadata(ensembleSize, - writeQuorumSize, ackQuorumSize, password, customMetadata); - registerMockLedgerMetadata(ledgerId, ledgerMetadata); - - result(newDeleteLedgerOp() - .withLedgerId(ledgerId) - .execute()); - } - - @Test(expected = BKClientClosedException.class) - public void testDeleteLedgerBookKeeperClosed() throws Exception { - closeBookkeeper(); - result(newDeleteLedgerOp() - .withLedgerId(ledgerId) - .execute()); - } - - protected LedgerMetadata generateLedgerMetadata(int ensembleSize, - int writeQuorumSize, int ackQuorumSize, byte[] password, - Map customMetadata) throws BKException.BKNotEnoughBookiesException { - return LedgerMetadataBuilder.create() - .withId(12L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .withPassword(password) - .withDigestType(BookKeeper.DigestType.CRC32.toApiDigestType()) - .withCustomMetadata(customMetadata) - .withCreationTime(System.currentTimeMillis()) - .newEnsembleEntry(0, generateNewEnsemble(ensembleSize)).build(); - } - - @Test - public void testCreateLedgerWithOpportunisticStriping() throws Exception { - - maxNumberOfAvailableBookies = 4; - int bigEnsembleSize = 15; - int expectedWriteQuorumSize = 4; - - ClientConfiguration config = new ClientConfiguration(); - config.setOpportunisticStriping(true); - setBookKeeperConfig(config); - - setNewGeneratedLedgerId(ledgerId); - WriteHandle writer = newCreateLedgerOp() - .withAckQuorumSize(expectedWriteQuorumSize) - .withEnsembleSize(bigEnsembleSize) - .withWriteQuorumSize(expectedWriteQuorumSize) - .withCustomMetadata(customMetadata) - .withPassword(password) - .execute() - .get(); - assertEquals(ledgerId, writer.getId()); - LedgerMetadata metadata = getLedgerMetadata(ledgerId); - assertEquals(expectedWriteQuorumSize, metadata.getEnsembleSize()); - assertEquals(expectedWriteQuorumSize, metadata.getAckQuorumSize()); - assertEquals(expectedWriteQuorumSize, metadata.getWriteQuorumSize()); - assertArrayEquals(password, metadata.getPassword()); - - } - - @Test(expected = BKException.BKNotEnoughBookiesException.class) - public void testNotEnoughBookies() throws Exception { - - maxNumberOfAvailableBookies = 1; - ClientConfiguration config = new ClientConfiguration(); - config.setOpportunisticStriping(false); - setBookKeeperConfig(config); - - setNewGeneratedLedgerId(ledgerId); - result(newCreateLedgerOp() - .withAckQuorumSize(ackQuorumSize) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withCustomMetadata(customMetadata) - .withPassword(password) - .execute()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/ExplicitLACWithWriteHandleAPITest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/ExplicitLACWithWriteHandleAPITest.java deleted file mode 100644 index 9917149ce64..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/ExplicitLACWithWriteHandleAPITest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client.api; - -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.TestUtils; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests about ExplicitLAC and {@link Handle} API. - */ -public class ExplicitLACWithWriteHandleAPITest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(ExplicitLACWithWriteHandleAPITest.class); - - public ExplicitLACWithWriteHandleAPITest() { - super(1); - } - - @Test - public void testUseExplicitLAC() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setExplictLacInterval(1000); - try (BookKeeper bkc = BookKeeper - .newBuilder(conf) - .build();) { - try (WriteHandle writer = bkc.newCreateLedgerOp() - .withAckQuorumSize(1) - .withEnsembleSize(1) - .withPassword(new byte[0]) - .withWriteQuorumSize(1) - .execute() - .get();) { - writer.append("foo".getBytes("utf-8")); - writer.append("foo".getBytes("utf-8")); - writer.append("foo".getBytes("utf-8")); - long expectedLastAddConfirmed = writer.append("foo".getBytes("utf-8")); - - // since BK 4.12.0 the reader automatically uses ExplicitLAC - try (ReadHandle r = bkc.newOpenLedgerOp() - .withRecovery(false) - .withPassword(new byte[0]) - .withLedgerId(writer.getId()) - .execute() - .get()) { - TestUtils.assertEventuallyTrue("ExplicitLAC did not ork", () -> { - try { - long value = r.readLastAddConfirmed(); - LOG.info("current value " + value + " vs " + expectedLastAddConfirmed); - return value == expectedLastAddConfirmed; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - }, 30, TimeUnit.SECONDS); - } - - } - - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/LedgerMetadataTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/LedgerMetadataTest.java deleted file mode 100644 index 7d7f6c19afc..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/LedgerMetadataTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.client.api; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.Iterator; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Bookkeeper Client API ledger metadata and ledgers listing test. - */ -public class LedgerMetadataTest extends BookKeeperClusterTestCase { - - public LedgerMetadataTest() { - super(3); - } - - @Test - public void testGetLedgerMetadata() - throws Exception { - - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - try (BookKeeper bkc = BookKeeper.newBuilder(conf).build();) { - long ledgerId; - try (WriteHandle l = bkc - .newCreateLedgerOp() - .withDigestType(DigestType.CRC32) - .withPassword("testPasswd".getBytes()) - .execute() - .get();) { - ledgerId = l.getId(); - } - - LedgerMetadata metadata = FutureUtils.result(bkc.getLedgerMetadata(ledgerId)); - assertEquals(ledgerId, metadata.getLedgerId()); - assertEquals(3, metadata.getEnsembleSize()); - assertEquals(2, metadata.getAckQuorumSize()); - assertEquals(2, metadata.getWriteQuorumSize()); - assertArrayEquals("testPasswd".getBytes(), metadata.getPassword()); - } - - } - - @Test - public void testListLedgers() - throws Exception { - int numOfLedgers = 10; - - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - try (BookKeeper bkc = BookKeeper.newBuilder(conf).build();) { - long[] ledgerIds = new long[numOfLedgers]; - for (int i = 0; i < numOfLedgers; i++) { - - try (WriteHandle l = bkc - .newCreateLedgerOp() - .withDigestType(DigestType.CRC32) - .withPassword("testPasswd".getBytes()) - .execute() - .get();) { - ledgerIds[i] = l.getId(); - } - } - - try (ListLedgersResult result = FutureUtils.result(bkc.newListLedgersOp().execute());) { - int count = 0; - - for (long ledgerId : result.toIterable()) { - assertEquals(ledgerIds[count++], ledgerId); - } - - assertEquals("Unexpected ledgers count", numOfLedgers, count); - try { - result.iterator(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - try { - result.toIterable(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - } - - try (ListLedgersResult result = FutureUtils.result(bkc.newListLedgersOp().execute());) { - int count = 0; - - for (LedgersIterator iterator = result.iterator(); iterator.hasNext();) { - long ledgerId = iterator.next(); - assertEquals(ledgerIds[count++], ledgerId); - - } - assertEquals("Unexpected ledgers count", numOfLedgers, count); - try { - result.iterator(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - try { - result.toIterable(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - } - } - - // check closed - { - ListLedgersResult result = FutureUtils.result(bkc.newListLedgersOp().execute()); - result.close(); - try { - result.toIterable(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - - try { - result.iterator(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - } - - { // iterator - ListLedgersResult result = FutureUtils.result(bkc.newListLedgersOp().execute()); - LedgersIterator it = result.iterator(); - result.close(); - try { - it.hasNext(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - - try { - it.next(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - } - - { // iterable - ListLedgersResult result = FutureUtils.result(bkc.newListLedgersOp().execute()); - Iterator it = result.toIterable().iterator(); - result.close(); - try { - it.hasNext(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - - try { - it.next(); - fail("Should thrown error"); - } catch (IllegalStateException e) { - // ok - } - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteAdvHandleTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteAdvHandleTest.java deleted file mode 100644 index 6c469c44e41..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteAdvHandleTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.client.api; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import java.nio.ByteBuffer; -import java.util.concurrent.LinkedBlockingQueue; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test for {@link WriteAdvHandle}. - */ -public class WriteAdvHandleTest { - - @Rule - public final TestName runtime = new TestName(); - - private final long entryId; - private final WriteAdvHandle handle = mock(WriteAdvHandle.class); - private final LinkedBlockingQueue entryQueue; - - public WriteAdvHandleTest() { - this.entryId = System.currentTimeMillis(); - this.entryQueue = new LinkedBlockingQueue<>(); - doAnswer(invocationOnMock -> { - ByteBuf buf = invocationOnMock.getArgument(1); - entryQueue.add(buf); - return FutureUtils.value(-1L); - }).when(handle).writeAsync(anyLong(), any(ByteBuf.class)); - when(handle.writeAsync(anyLong(), any(byte[].class))).thenCallRealMethod(); - when(handle.writeAsync(anyLong(), any(byte[].class), anyInt(), anyInt())).thenCallRealMethod(); - when(handle.writeAsync(anyLong(), any(ByteBuffer.class))).thenCallRealMethod(); - } - - @Test - public void testAppendBytes() throws Exception { - byte[] testData = runtime.getMethodName().getBytes(UTF_8); - handle.writeAsync(entryId, testData); - - ByteBuf buffer = entryQueue.take(); - byte[] bufferData = ByteBufUtil.getBytes(buffer); - assertArrayEquals(testData, bufferData); - verify(handle, times(1)).writeAsync(eq(entryId), any(ByteBuf.class)); - } - - @Test - public void testAppendBytes2() throws Exception { - byte[] testData = runtime.getMethodName().getBytes(UTF_8); - handle.writeAsync(entryId, testData, 1, testData.length / 2); - byte[] expectedData = new byte[testData.length / 2]; - System.arraycopy(testData, 1, expectedData, 0, testData.length / 2); - - ByteBuf buffer = entryQueue.take(); - byte[] bufferData = ByteBufUtil.getBytes(buffer); - assertArrayEquals(expectedData, bufferData); - verify(handle, times(1)).writeAsync(eq(entryId), any(ByteBuf.class)); - } - - @Test - public void testAppendByteBuffer() throws Exception { - byte[] testData = runtime.getMethodName().getBytes(UTF_8); - handle.writeAsync(entryId, ByteBuffer.wrap(testData, 1, testData.length / 2)); - byte[] expectedData = new byte[testData.length / 2]; - System.arraycopy(testData, 1, expectedData, 0, testData.length / 2); - - ByteBuf buffer = entryQueue.take(); - byte[] bufferData = ByteBufUtil.getBytes(buffer); - assertArrayEquals(expectedData, bufferData); - verify(handle, times(1)).writeAsync(eq(entryId), any(ByteBuf.class)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteFlagTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteFlagTest.java deleted file mode 100644 index 902bb50a7de..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteFlagTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.client.api; - -import static org.apache.bookkeeper.client.api.WriteFlag.DEFERRED_SYNC; -import static org.junit.Assert.assertEquals; - -import java.util.EnumSet; -import org.junit.Test; - -/** - * Unit tests for WriteFlag. - */ -public class WriteFlagTest { - - private static final int NONE = 0; - - @Test - public void testGetWriteFlagsDeferredSync() { - assertEquals(EnumSet.of(DEFERRED_SYNC), - WriteFlag.getWriteFlags(DEFERRED_SYNC.getValue())); - } - - @Test - public void testGetWriteFlagsNone() { - assertEquals(WriteFlag.NONE, - WriteFlag.getWriteFlags(NONE)); - } - - @Test(expected = NullPointerException.class) - public void testGetWriteFlagsValueNull() { - WriteFlag.getWriteFlagsValue(null); - } - - @Test - public void testGetWriteFlagsValueEmpty() { - assertEquals(0, WriteFlag.getWriteFlagsValue(WriteFlag.NONE)); - } - - @Test - public void testGetWriteFlagsValueDeferredSync() { - assertEquals(1, WriteFlag.getWriteFlagsValue(EnumSet.of(DEFERRED_SYNC))); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteHandleTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteHandleTest.java deleted file mode 100644 index 576d5537715..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteHandleTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.client.api; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import java.nio.ByteBuffer; -import java.util.concurrent.LinkedBlockingQueue; -import lombok.extern.slf4j.Slf4j; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test for the default methods in {@link WriteHandle}. - */ -@Slf4j -public class WriteHandleTest { - - @Rule - public final TestName runtime = new TestName(); - - private final WriteHandle handle = mock(WriteHandle.class); - private final LinkedBlockingQueue entryQueue; - - public WriteHandleTest() throws Exception { - this.entryQueue = new LinkedBlockingQueue<>(); - doAnswer(invocationOnMock -> { - ByteBuf buf = invocationOnMock.getArgument(0); - entryQueue.add(buf); - return -1L; - }).when(handle).append(any(ByteBuf.class)); - when(handle.append(any(byte[].class))).thenCallRealMethod(); - when(handle.append(any(byte[].class), anyInt(), anyInt())).thenCallRealMethod(); - when(handle.append(any(ByteBuffer.class))).thenCallRealMethod(); - } - - @Test - public void testAppendBytes() throws Exception { - byte[] testData = runtime.getMethodName().getBytes(UTF_8); - handle.append(testData); - - ByteBuf buffer = entryQueue.take(); - byte[] bufferData = ByteBufUtil.getBytes(buffer); - assertArrayEquals(testData, bufferData); - verify(handle, times(1)).append(any(ByteBuf.class)); - } - - @Test - public void testAppendBytes2() throws Exception { - byte[] testData = runtime.getMethodName().getBytes(UTF_8); - handle.append(testData, 1, testData.length / 2); - byte[] expectedData = new byte[testData.length / 2]; - System.arraycopy(testData, 1, expectedData, 0, testData.length / 2); - - ByteBuf buffer = entryQueue.take(); - byte[] bufferData = ByteBufUtil.getBytes(buffer); - assertArrayEquals(expectedData, bufferData); - verify(handle, times(1)).append(any(ByteBuf.class)); - } - - @Test - public void testAppendByteBuffer() throws Exception { - byte[] testData = runtime.getMethodName().getBytes(UTF_8); - handle.append(ByteBuffer.wrap(testData, 1, testData.length / 2)); - byte[] expectedData = new byte[testData.length / 2]; - System.arraycopy(testData, 1, expectedData, 0, testData.length / 2); - - ByteBuf buffer = entryQueue.take(); - byte[] bufferData = ByteBufUtil.getBytes(buffer); - assertArrayEquals(expectedData, bufferData); - verify(handle, times(1)).append(any(ByteBuf.class)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntriesImplTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntriesImplTest.java deleted file mode 100644 index ff7117c8e2e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntriesImplTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.client.impl; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import org.apache.bookkeeper.client.api.LedgerEntry; -import org.junit.After; -import org.junit.Test; - -/** - * Unit test for {@link LedgerEntriesImpl}. - */ -public class LedgerEntriesImplTest { - private final int entryNumber = 7; - private LedgerEntriesImpl ledgerEntriesImpl; - private final List entryList = Lists.newArrayList(); - - // content for each entry - private final long ledgerId = 1234L; - private final long entryId = 5678L; - private final long length = 9876L; - private final byte[] dataBytes = "test-ledger-entry-impl".getBytes(UTF_8); - private final ArrayList bufs = Lists.newArrayListWithExpectedSize(entryNumber); - - public LedgerEntriesImplTest () { - for (int i = 0; i < entryNumber; i++) { - ByteBuf buf = Unpooled.wrappedBuffer(dataBytes); - bufs.add(buf); - - entryList.add(LedgerEntryImpl.create(ledgerId + i, - entryId + i, - length + i, - buf)); - } - - ledgerEntriesImpl = LedgerEntriesImpl.create(entryList); - } - - @After - public void tearDown() { - ledgerEntriesImpl.close(); - - // References should be released after close. - bufs.forEach(byteBuf -> assertEquals(0, byteBuf.refCnt())); - - try { - ledgerEntriesImpl.getEntry(entryId); - fail("should fail getEntry after close"); - } catch (NullPointerException e) { - // expected behavior - } - - try { - ledgerEntriesImpl.iterator(); - fail("should fail iterator after close"); - } catch (NullPointerException e) { - // expected behavior - } - } - - @Test - public void testGetEntry() { - for (int i = 0; i < entryNumber; i++) { - LedgerEntry entry = ledgerEntriesImpl.getEntry(entryId + i); - assertEquals(entryList.get(i).getLedgerId(), entry.getLedgerId()); - assertEquals(entryList.get(i).getEntryId(), entry.getEntryId()); - assertEquals(entryList.get(i).getLength(), entry.getLength()); - - ByteBuf buf = entry.getEntryBuffer(); - byte[] content = new byte[buf.readableBytes()]; - buf.readBytes(content); - assertArrayEquals(dataBytes, content); - - assertEquals(1, entry.getEntryBuffer().refCnt()); - } - - try { - LedgerEntry entry = ledgerEntriesImpl.getEntry(entryId - 1); - fail("Should get IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException e) { - // expected behavior - } - - try { - LedgerEntry entry = ledgerEntriesImpl.getEntry(entryId + entryNumber); - fail("Should get IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException e) { - // expected behavior - } - } - - @Test - public void testIterator() { - Iterator entryIterator = ledgerEntriesImpl.iterator(); - entryIterator.forEachRemaining(ledgerEntry -> assertEquals(1, ledgerEntry.getEntryBuffer().refCnt())); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntryImplTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntryImplTest.java deleted file mode 100644 index 2b7cc0f6737..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntryImplTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.client.impl; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.nio.ByteBuffer; -import org.junit.After; -import org.junit.Test; - -/** - * Unit test for {@link LedgerEntryImpl}. - */ -public class LedgerEntryImplTest { - - private final long ledgerId; - private final long entryId; - private final long length; - private final byte[] dataBytes; - private final ByteBuf dataBuf; - private final LedgerEntryImpl entryImpl; - - public LedgerEntryImplTest() { - this.ledgerId = 1234L; - this.entryId = 3579L; - this.length = 200L; - this.dataBytes = "test-ledger-entry-impl".getBytes(UTF_8); - this.dataBuf = Unpooled.wrappedBuffer(dataBytes); - this.entryImpl = LedgerEntryImpl.create( - ledgerId, - entryId, - length, - dataBuf); - } - - @After - public void teardown() { - this.entryImpl.close(); - assertEquals(0, dataBuf.refCnt()); - } - - @Test - public void testGetters() { - assertEquals(ledgerId, entryImpl.getLedgerId()); - assertEquals(entryId, entryImpl.getEntryId()); - assertEquals(length, entryImpl.getLength()); - assertArrayEquals(dataBytes, entryImpl.getEntryBytes()); - // getEntry should not modify readerIndex - assertEquals(0, entryImpl.getEntryBuffer().readerIndex()); - assertEquals(dataBytes.length, entryImpl.getEntryBuffer().readableBytes()); - // getEntryNioBuffer should not modify readerIndex - ByteBuffer nioBuffer = entryImpl.getEntryNioBuffer(); - assertEquals(dataBytes.length, nioBuffer.remaining()); - byte[] readBytes = new byte[nioBuffer.remaining()]; - nioBuffer.get(readBytes); - assertArrayEquals(dataBytes, readBytes); - assertEquals(0, entryImpl.getEntryBuffer().readerIndex()); - assertEquals(dataBytes.length, entryImpl.getEntryBuffer().readableBytes()); - } - - @Test - public void testSetters() { - assertEquals(ledgerId, entryImpl.getLedgerId()); - assertEquals(entryId, entryImpl.getEntryId()); - assertEquals(length, entryImpl.getLength()); - - entryImpl.setLength(length * 2); - assertEquals(length * 2, entryImpl.getLength()); - - entryImpl.setEntryId(entryId * 2); - assertEquals(entryId * 2, entryImpl.getEntryId()); - - byte[] anotherBytes = "another-ledger-entry-impl".getBytes(UTF_8); - ByteBuf anotherBuf = Unpooled.wrappedBuffer(anotherBytes); - - entryImpl.setEntryBuf(anotherBuf); - // set buf should release the original buf - assertEquals(0, dataBuf.refCnt()); - } - - @Test - public void testDuplicate() { - LedgerEntryImpl duplicatedEntry = LedgerEntryImpl.duplicate(entryImpl); - - // the underneath buffer should have 2 entries referencing it - assertEquals(2, dataBuf.refCnt()); - - assertEquals(ledgerId, duplicatedEntry.getLedgerId()); - assertEquals(entryId, duplicatedEntry.getEntryId()); - assertEquals(length, duplicatedEntry.getLength()); - assertArrayEquals(dataBytes, duplicatedEntry.getEntryBytes()); - - duplicatedEntry.close(); - assertEquals(1, dataBuf.refCnt()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/AbstractConfigurationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/AbstractConfigurationTest.java deleted file mode 100644 index a6333a47d32..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/AbstractConfigurationTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.conf; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.mock; - -import org.apache.bookkeeper.common.allocator.LeakDetectionPolicy; -import org.apache.bookkeeper.meta.AbstractZkLedgerManagerFactory; -import org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LongHierarchicalLedgerManagerFactory; -import org.apache.commons.configuration.ConfigurationException; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link AbstractConfiguration}. - */ -public class AbstractConfigurationTest { - - private static final String DEFAULT_METADATA_SERVICE_URI = - "zk+null://127.0.0.1/path/to/ledgers"; - private static final String HIERARCHICAL_METADATA_SERVICE_URI = - "zk+hierarchical://127.0.0.1/path/to/ledgers"; - private static final String FLAT_METADATA_SERVICE_URI = - "zk+flat://127.0.0.1/path/to/ledgers"; - private static final String LONGHIERARCHICAL_METADATA_SERVICE_URI = - "zk+longhierarchical://127.0.0.1/path/to/ledgers"; - private static final String MS_METADATA_SERVICE_URI = - "zk+ms://127.0.0.1/path/to/ledgers"; - - private AbstractConfiguration conf; - - @Before - @SuppressWarnings("deprecation") - public void setup() { - this.conf = new ClientConfiguration(); - this.conf.setZkServers("127.0.0.1"); - this.conf.setZkLedgersRootPath("/path/to/ledgers"); - } - - @Test - public void testDefaultServiceUri() throws Exception { - assertEquals( - DEFAULT_METADATA_SERVICE_URI, - conf.getMetadataServiceUri()); - } - - @Test - public void testSetMetadataServiceUri() throws Exception { - assertEquals( - DEFAULT_METADATA_SERVICE_URI, - conf.getMetadataServiceUri()); - String serviceUri = "etcd://128.0.0.1/key/prefix"; - conf.setMetadataServiceUri(serviceUri); - assertEquals( - "Service URI should be changed to " + serviceUri, - serviceUri, - conf.getMetadataServiceUri()); - } - - @SuppressWarnings({ "unchecked" }) - @Test(expected = ConfigurationException.class) - public void testUnsupportedLedgerManagerFactory() throws Exception { - LedgerManagerFactory mockFactory = mock(LedgerManagerFactory.class, CALLS_REAL_METHODS); - conf.setLedgerManagerFactoryClass(mockFactory.getClass()); - conf.getMetadataServiceUri(); - } - - @SuppressWarnings({ "deprecation", "unchecked" }) - @Test - public void testFlatLedgerManagerUri() throws Exception { - conf.setLedgerManagerFactoryClass(org.apache.bookkeeper.meta.FlatLedgerManagerFactory.class); - assertEquals( - FLAT_METADATA_SERVICE_URI, - conf.getMetadataServiceUri()); - } - - @SuppressWarnings({ "unchecked" }) - @Test - public void testHierarchicalLedgerManagerUri() throws Exception { - conf.setLedgerManagerFactoryClass(HierarchicalLedgerManagerFactory.class); - assertEquals( - HIERARCHICAL_METADATA_SERVICE_URI, - conf.getMetadataServiceUri()); - } - - @SuppressWarnings({ "unchecked" }) - @Test - public void testLongHierarchicalLedgerManagerUri() throws Exception { - conf.setLedgerManagerFactoryClass(LongHierarchicalLedgerManagerFactory.class); - assertEquals( - LONGHIERARCHICAL_METADATA_SERVICE_URI, - conf.getMetadataServiceUri()); - } - - @SuppressWarnings({ "unchecked", "deprecation" }) - @Test - public void testMsLedgerManagerUri() throws Exception { - conf.setLedgerManagerFactoryClass( - org.apache.bookkeeper.meta.MSLedgerManagerFactory.class); - assertEquals( - MS_METADATA_SERVICE_URI, - conf.getMetadataServiceUri()); - } - - @SuppressWarnings({ "unchecked" }) - @Test(expected = IllegalArgumentException.class) - public void testUnknownZkLedgerManagerFactory() throws Exception { - AbstractZkLedgerManagerFactory mockZkFactory = - mock(AbstractZkLedgerManagerFactory.class, CALLS_REAL_METHODS); - conf.setLedgerManagerFactoryClass(mockZkFactory.getClass()); - conf.getMetadataServiceUri(); - } - - @Test - public void testAllocatorLeakDetectionPolicy() { - String nettyOldLevelKey = "io.netty.leakDetectionLevel"; - String nettyLevelKey = "io.netty.leakDetection.level"; - - String nettyOldLevelStr = System.getProperty(nettyOldLevelKey); - String nettyLevelStr = System.getProperty(nettyLevelKey); - - //Remove netty property for test. - System.getProperties().remove(nettyOldLevelKey); - System.getProperties().remove(nettyLevelKey); - - assertEquals(LeakDetectionPolicy.Disabled, conf.getAllocatorLeakDetectionPolicy()); - - System.getProperties().put(nettyOldLevelKey, "zazaza"); - assertEquals(LeakDetectionPolicy.Disabled, conf.getAllocatorLeakDetectionPolicy()); - - conf.setProperty(AbstractConfiguration.ALLOCATOR_LEAK_DETECTION_POLICY, "zazaza"); - assertEquals(LeakDetectionPolicy.Disabled, conf.getAllocatorLeakDetectionPolicy()); - - System.getProperties().put(nettyOldLevelKey, "simple"); - assertEquals(LeakDetectionPolicy.Simple, conf.getAllocatorLeakDetectionPolicy()); - - System.getProperties().put(nettyLevelKey, "disabled"); - assertEquals(LeakDetectionPolicy.Disabled, conf.getAllocatorLeakDetectionPolicy()); - - System.getProperties().put(nettyLevelKey, "advanCed"); - assertEquals(LeakDetectionPolicy.Advanced, conf.getAllocatorLeakDetectionPolicy()); - - conf.setProperty(AbstractConfiguration.ALLOCATOR_LEAK_DETECTION_POLICY, "simPle"); - assertEquals(LeakDetectionPolicy.Advanced, conf.getAllocatorLeakDetectionPolicy()); - - conf.setProperty(AbstractConfiguration.ALLOCATOR_LEAK_DETECTION_POLICY, "advanCed"); - assertEquals(LeakDetectionPolicy.Advanced, conf.getAllocatorLeakDetectionPolicy()); - - conf.setProperty(AbstractConfiguration.ALLOCATOR_LEAK_DETECTION_POLICY, "paranoiD"); - assertEquals(LeakDetectionPolicy.Paranoid, conf.getAllocatorLeakDetectionPolicy()); - - System.getProperties().remove(nettyOldLevelKey); - System.getProperties().remove(nettyLevelKey); - //Revert the netty properties. - if (nettyOldLevelStr != null) { - System.getProperties().put(nettyOldLevelKey, nettyOldLevelStr); - } - if (nettyLevelStr != null) { - System.getProperties().put(nettyLevelKey, nettyLevelStr); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/NoSystemPropertiesConfigurationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/NoSystemPropertiesConfigurationTest.java deleted file mode 100644 index 5fe86aa209d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/NoSystemPropertiesConfigurationTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.conf; - -import static org.junit.Assert.assertEquals; - -import java.util.NoSuchElementException; -import org.junit.Test; - -/** - * Test Configuration API. - * - * @see SystemPropertiesConfigurationTest - */ -public class NoSystemPropertiesConfigurationTest { - - static { - // this property is read when AbstractConfiguration class is loaded. - // this test will work as expected only using a new JVM (or classloader) for the test - System.setProperty(ClientConfiguration.THROTTLE, "10"); - System.setProperty(ClientConfiguration.CLIENT_TCP_USER_TIMEOUT_MILLIS, "20000"); - } - - @Test(expected = NoSuchElementException.class) - public void testUseSystemProperty() { - ClientConfiguration clientConfiguration = new ClientConfiguration(); - assertEquals(5000, clientConfiguration.getThrottleValue()); - // This should throw NoSuchElementException if the property has not been set. - clientConfiguration.getTcpUserTimeoutMillis(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/SystemPropertiesConfigurationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/SystemPropertiesConfigurationTest.java deleted file mode 100644 index 8ce89523354..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/SystemPropertiesConfigurationTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.conf; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -/** - * Test Configuration API. - * - * @see NoSystemPropertiesConfigurationTest - */ -public class SystemPropertiesConfigurationTest { - - static { - // this property is read when AbstractConfiguration class is loaded. - // this test will work as expected only using a new JVM (or classloader) for the test - System.setProperty(AbstractConfiguration.READ_SYSTEM_PROPERTIES_PROPERTY, "true"); - System.setProperty(ClientConfiguration.THROTTLE, "10"); - System.setProperty(ClientConfiguration.CLIENT_TCP_USER_TIMEOUT_MILLIS, "20000"); - } - - @Test - public void testUseSystemProperty() { - ClientConfiguration clientConfiguration = new ClientConfiguration(); - assertEquals(10, clientConfiguration.getThrottleValue()); - assertEquals(20000, clientConfiguration.getTcpUserTimeoutMillis()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestBKConfiguration.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestBKConfiguration.java deleted file mode 100644 index a716f0e18a2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestBKConfiguration.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.conf; - -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Collections; -import java.util.Enumeration; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.common.allocator.PoolingPolicy; -import org.apache.bookkeeper.util.PortManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the BK configuration object. - */ -public class TestBKConfiguration { - - static final Logger LOG = LoggerFactory.getLogger(TestBKConfiguration.class); - - /** - * Loopback interface is set as the listening interface and allowloopback is - * set to true in this server config. - * - *

If the caller doesn't want loopback address, then listeningInterface - * should be set back to null. - */ - public static ServerConfiguration newServerConfiguration() { - ServerConfiguration confReturn = new ServerConfiguration(); - confReturn.setTLSEnabledProtocols("TLSv1.2,TLSv1.1"); - confReturn.setJournalFlushWhenQueueEmpty(true); - // enable journal format version - confReturn.setJournalFormatVersionToWrite(5); - confReturn.setAllowEphemeralPorts(false); - confReturn.setBookiePort(PortManager.nextFreePort()); - confReturn.setGcWaitTime(1000); - confReturn.setDiskUsageThreshold(0.999f); - confReturn.setDiskUsageWarnThreshold(0.99f); - confReturn.setAllocatorPoolingPolicy(PoolingPolicy.UnpooledHeap); - confReturn.setProperty(DbLedgerStorage.WRITE_CACHE_MAX_SIZE_MB, 4); - confReturn.setProperty(DbLedgerStorage.READ_AHEAD_CACHE_MAX_SIZE_MB, 4); - /** - * if testcase has zk error,just try 0 time for fast running - */ - confReturn.setZkRetryBackoffMaxRetries(0); - setLoopbackInterfaceAndAllowLoopback(confReturn); - return confReturn; - } - - private static String getLoopbackInterfaceName() { - try { - Enumeration nifs = NetworkInterface.getNetworkInterfaces(); - for (NetworkInterface nif : Collections.list(nifs)) { - if (nif.isLoopback()) { - return nif.getName(); - } - } - } catch (SocketException se) { - LOG.warn("Exception while figuring out loopback interface. Will use null.", se); - return null; - } - LOG.warn("Unable to deduce loopback interface. Will use null"); - return null; - } - - public static ServerConfiguration setLoopbackInterfaceAndAllowLoopback(ServerConfiguration serverConf) { - serverConf.setListeningInterface(getLoopbackInterfaceName()); - serverConf.setAllowLoopback(true); - return serverConf; - } - - public static ClientConfiguration newClientConfiguration() { - ClientConfiguration clientConfiguration = new ClientConfiguration(); - clientConfiguration.setTLSEnabledProtocols("TLSv1.2,TLSv1.1"); - /** - * if testcase has zk error,just try 0 time for fast running - */ - clientConfiguration.setZkRetryBackoffMaxRetries(0); - return clientConfiguration; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestServerConfiguration.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestServerConfiguration.java deleted file mode 100644 index 04ac87818f7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestServerConfiguration.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.conf; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.apache.commons.configuration.ConfigurationException; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link ServerConfiguration}. - */ -public class TestServerConfiguration { - - private final ServerConfiguration serverConf; - - public TestServerConfiguration() { - serverConf = new ServerConfiguration(); - } - - @Before - public void setup() throws Exception { - serverConf.loadConf( - getClass().getClassLoader().getResource("bk_server.conf")); - } - - @Test - public void testEphemeralPortsAllowed() throws ConfigurationException { - ServerConfiguration conf = new ServerConfiguration(); - conf.setAllowEphemeralPorts(true); - conf.setBookiePort(0); - - conf.validate(); - assertTrue(true); - } - - @Test(expected = ConfigurationException.class) - public void testEphemeralPortsDisallowed() throws ConfigurationException { - ServerConfiguration conf = new ServerConfiguration(); - conf.setAllowEphemeralPorts(false); - conf.setBookiePort(0); - conf.validate(); - } - - @Test - public void testSetExtraServerComponents() { - ServerConfiguration conf = new ServerConfiguration(); - assertNull(conf.getExtraServerComponents()); - String[] components = new String[] { - "test1", "test2", "test3" - }; - conf.setExtraServerComponents(components); - assertArrayEquals(components, conf.getExtraServerComponents()); - } - - @Test - public void testGetExtraServerComponents() { - String[] components = new String[] { - "test1", "test2", "test3" - }; - assertArrayEquals(components, serverConf.getExtraServerComponents()); - } - - @Test(expected = ConfigurationException.class) - public void testMismatchofJournalAndFileInfoVersionsOlderJournalVersion() throws ConfigurationException { - ServerConfiguration conf = new ServerConfiguration(); - conf.setJournalFormatVersionToWrite(5); - conf.setFileInfoFormatVersionToWrite(1); - conf.validate(); - } - - @Test(expected = ConfigurationException.class) - public void testMismatchofJournalAndFileInfoVersionsOlderFileInfoVersion() throws ConfigurationException { - ServerConfiguration conf = new ServerConfiguration(); - conf.setJournalFormatVersionToWrite(6); - conf.setFileInfoFormatVersionToWrite(0); - conf.validate(); - } - - @Test - public void testValidityOfJournalAndFileInfoVersions() throws ConfigurationException { - ServerConfiguration conf = new ServerConfiguration(); - conf.setJournalFormatVersionToWrite(5); - conf.setFileInfoFormatVersionToWrite(0); - conf.validate(); - - conf = new ServerConfiguration(); - conf.setJournalFormatVersionToWrite(6); - conf.setFileInfoFormatVersionToWrite(1); - conf.validate(); - } - - @Test - public void testEntryLogSizeLimit() throws ConfigurationException { - ServerConfiguration conf = new ServerConfiguration(); - try { - conf.setEntryLogSizeLimit(-1); - fail("should fail setEntryLogSizeLimit since `logSizeLimit` is too small"); - } catch (IllegalArgumentException iae) { - // expected - } - try { - conf.setProperty("logSizeLimit", "-1"); - conf.validate(); - fail("Invalid configuration since `logSizeLimit` is too small"); - } catch (ConfigurationException ce) { - // expected - } - - try { - conf.setEntryLogSizeLimit(2 * 1024 * 1024 * 1024L - 1); - fail("Should fail setEntryLogSizeLimit size `logSizeLimit` is too large"); - } catch (IllegalArgumentException iae) { - // expected - } - try { - conf.validate(); - fail("Invalid configuration since `logSizeLimit` is too large"); - } catch (ConfigurationException ce) { - // expected - } - - conf.setEntryLogSizeLimit(512 * 1024 * 1024); - conf.validate(); - assertEquals(512 * 1024 * 1024, conf.getEntryLogSizeLimit()); - - conf.setEntryLogSizeLimit(1073741824); - conf.validate(); - assertEquals(1073741824, conf.getEntryLogSizeLimit()); - } - - @Test - public void testCompactionSettings() throws ConfigurationException { - ServerConfiguration conf = new ServerConfiguration(); - long major, minor; - - // Default Values - major = conf.getMajorCompactionMaxTimeMillis(); - minor = conf.getMinorCompactionMaxTimeMillis(); - Assert.assertEquals(-1, major); - Assert.assertEquals(-1, minor); - - // Set values major then minor - conf.setMajorCompactionMaxTimeMillis(500).setMinorCompactionMaxTimeMillis(250); - major = conf.getMajorCompactionMaxTimeMillis(); - minor = conf.getMinorCompactionMaxTimeMillis(); - Assert.assertEquals(500, major); - Assert.assertEquals(250, minor); - - // Set values minor then major - conf.setMinorCompactionMaxTimeMillis(150).setMajorCompactionMaxTimeMillis(1500); - major = conf.getMajorCompactionMaxTimeMillis(); - minor = conf.getMinorCompactionMaxTimeMillis(); - Assert.assertEquals(1500, major); - Assert.assertEquals(150, minor); - - // Default Values - major = conf.getMajorCompactionInterval(); - minor = conf.getMinorCompactionInterval(); - Assert.assertEquals(3600, minor); - Assert.assertEquals(86400, major); - - // Set values major then minor - conf.setMajorCompactionInterval(43200).setMinorCompactionInterval(1800); - major = conf.getMajorCompactionInterval(); - minor = conf.getMinorCompactionInterval(); - Assert.assertEquals(1800, minor); - Assert.assertEquals(43200, major); - - // Set values minor then major - conf.setMinorCompactionInterval(900).setMajorCompactionInterval(21700); - major = conf.getMajorCompactionInterval(); - minor = conf.getMinorCompactionInterval(); - Assert.assertEquals(900, minor); - Assert.assertEquals(21700, major); - - conf.setMinorCompactionInterval(500); - try { - conf.validate(); - fail(); - } catch (ConfigurationException ignore) { - } - - conf.setMinorCompactionInterval(600); - conf.validate(); - - conf.setMajorCompactionInterval(550); - try { - conf.validate(); - fail(); - } catch (ConfigurationException ignore) { - } - - conf.setMajorCompactionInterval(600); - conf.validate(); - - // Default Values - double majorThreshold, minorThreshold; - majorThreshold = conf.getMajorCompactionThreshold(); - minorThreshold = conf.getMinorCompactionThreshold(); - Assert.assertEquals(0.8, majorThreshold, 0.00001); - Assert.assertEquals(0.2, minorThreshold, 0.00001); - - // Set values major then minor - conf.setMajorCompactionThreshold(0.7).setMinorCompactionThreshold(0.1); - majorThreshold = conf.getMajorCompactionThreshold(); - minorThreshold = conf.getMinorCompactionThreshold(); - Assert.assertEquals(0.7, majorThreshold, 0.00001); - Assert.assertEquals(0.1, minorThreshold, 0.00001); - - // Set values minor then major - conf.setMinorCompactionThreshold(0.3).setMajorCompactionThreshold(0.6); - majorThreshold = conf.getMajorCompactionThreshold(); - minorThreshold = conf.getMinorCompactionThreshold(); - Assert.assertEquals(0.6, majorThreshold, 0.00001); - Assert.assertEquals(0.3, minorThreshold, 0.00001); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/AbstractTestZkRegistrationClient.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/AbstractTestZkRegistrationClient.java deleted file mode 100644 index 127dd4b28d8..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/AbstractTestZkRegistrationClient.java +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.discover; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.collect; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.apache.bookkeeper.common.testing.MoreAsserts.assertSetEquals; -import static org.apache.bookkeeper.discover.ZKRegistrationClient.ZK_CONNECT_BACKOFF_MS; -import static org.apache.bookkeeper.util.BookKeeperConstants.AVAILABLE_NODE; -import static org.apache.bookkeeper.util.BookKeeperConstants.COOKIE_NODE; -import static org.apache.bookkeeper.util.BookKeeperConstants.READONLY; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import java.time.Duration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException.ZKException; -import org.apache.bookkeeper.common.testing.executors.MockExecutorController; -import org.apache.bookkeeper.discover.RegistrationClient.RegistrationListener; -import org.apache.bookkeeper.discover.ZKRegistrationClient.WatchTask; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.bookkeeper.zookeeper.MockZooKeeperTestCase; -import org.apache.zookeeper.AsyncCallback.Children2Callback; -import org.apache.zookeeper.KeeperException.Code; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test of {@link RegistrationClient}. - */ -@RunWith(MockitoJUnitRunner.Silent.class) -@Slf4j -public abstract class AbstractTestZkRegistrationClient extends MockZooKeeperTestCase { - - - - @Rule - public final TestName runtime = new TestName(); - - private String ledgersPath; - private String regPath; - private String regAllPath; - private String regReadonlyPath; - private ZKRegistrationClient zkRegistrationClient; - private ScheduledExecutorService mockExecutor; - private MockExecutorController controller; - - private final boolean bookieAddressChangeTracking; - - public AbstractTestZkRegistrationClient(boolean bookieAddressChangeTracking) { - this.bookieAddressChangeTracking = bookieAddressChangeTracking; - } - - - @Override - @Before - public void setup() throws Exception { - super.setup(); - - this.ledgersPath = "/" + runtime.getMethodName(); - this.regPath = ledgersPath + "/" + AVAILABLE_NODE; - this.regAllPath = ledgersPath + "/" + COOKIE_NODE; - this.regReadonlyPath = regPath + "/" + READONLY; - this.mockExecutor = mock(ScheduledExecutorService.class); - this.controller = new MockExecutorController() - .controlExecute(mockExecutor) - .controlSubmit(mockExecutor) - .controlSchedule(mockExecutor) - .controlScheduleAtFixedRate(mockExecutor, 10); - this.zkRegistrationClient = new ZKRegistrationClient( - mockZk, - ledgersPath, - mockExecutor, - bookieAddressChangeTracking - ); - assertEquals(bookieAddressChangeTracking, zkRegistrationClient.isBookieAddressTracking()); - } - - @After - public void teardown() throws Exception{ - super.teardown(); - - if (null != zkRegistrationClient) { - zkRegistrationClient.close(); - } - } - - private static Set prepareNBookies(int num) { - Set bookies = new HashSet<>(); - for (int i = 0; i < num; i++) { - bookies.add(new BookieSocketAddress("127.0.0.1", 3181 + i).toBookieId()); - } - return bookies; - } - - private void prepareReadBookieServiceInfo(BookieId address, boolean readonly) throws Exception { - if (readonly) { - mockZkGetData(regPath + "/" + address.toString(), - zkRegistrationClient.isBookieAddressTracking(), - Code.NONODE.intValue(), - new byte[] {}, - new Stat()); - mockZkGetData(regReadonlyPath + "/" + address, - zkRegistrationClient.isBookieAddressTracking(), - Code.OK.intValue(), - new byte[] {}, - new Stat()); - } else { - mockZkGetData(regPath + "/" + address.toString(), - zkRegistrationClient.isBookieAddressTracking(), - Code.OK.intValue(), - new byte[] {}, - new Stat()); - mockZkGetData(regReadonlyPath + "/" + address, - zkRegistrationClient.isBookieAddressTracking(), - Code.NONODE.intValue(), - new byte[] {}, - new Stat()); - } - } - - @Test - public void testGetWritableBookies() throws Exception { - Set addresses = prepareNBookies(10); - List children = Lists.newArrayList(); - for (BookieId address : addresses) { - children.add(address.toString()); - prepareReadBookieServiceInfo(address, false); - } - - Stat stat = mock(Stat.class); - when(stat.getCversion()).thenReturn(1234); - mockGetChildren( - regPath, false, - Code.OK.intValue(), children, stat); - - Versioned> result = - result(zkRegistrationClient.getWritableBookies()); - - assertEquals(new LongVersion(1234), result.getVersion()); - assertSetEquals( - addresses, result.getValue()); - } - - @Test - public void testGetAllBookies() throws Exception { - Set addresses = prepareNBookies(10); - List children = Lists.newArrayList(); - - int i = 0; - for (BookieId address : addresses) { - children.add(address.toString()); - boolean readonly = i++ % 2 == 0; - prepareReadBookieServiceInfo(address, readonly); - } - Stat stat = mock(Stat.class); - when(stat.getCversion()).thenReturn(1234); - mockGetChildren( - regAllPath, false, - Code.OK.intValue(), children, stat); - - Versioned> result = - result(zkRegistrationClient.getAllBookies()); - - assertEquals(new LongVersion(1234), result.getVersion()); - assertSetEquals( - addresses, result.getValue()); - } - - @Test - public void testGetReadOnlyBookies() throws Exception { - Set addresses = prepareNBookies(10); - List children = Lists.newArrayList(); - for (BookieId address : addresses) { - children.add(address.toString()); - prepareReadBookieServiceInfo(address, false); - } - Stat stat = mock(Stat.class); - when(stat.getCversion()).thenReturn(1234); - mockGetChildren( - regReadonlyPath, false, - Code.OK.intValue(), children, stat); - - Versioned> result = - result(zkRegistrationClient.getReadOnlyBookies()); - - assertEquals(new LongVersion(1234), result.getVersion()); - assertSetEquals( - addresses, result.getValue()); - } - - @Test - public void testGetWritableBookiesFailure() throws Exception { - mockGetChildren( - regPath, false, - Code.NONODE.intValue(), null, null); - - try { - result(zkRegistrationClient.getWritableBookies()); - fail("Should fail to get writable bookies"); - } catch (ZKException zke) { - // expected to throw zookeeper exception - } - } - - @Test - public void testGetAllBookiesFailure() throws Exception { - mockGetChildren( - regAllPath, false, - Code.NONODE.intValue(), null, null); - - try { - result(zkRegistrationClient.getAllBookies()); - fail("Should fail to get all bookies"); - } catch (ZKException zke) { - // expected to throw zookeeper exception - } - } - - @Test - public void testGetReadOnlyBookiesFailure() throws Exception { - mockGetChildren( - regReadonlyPath, false, - Code.NONODE.intValue(), null, null); - - try { - result(zkRegistrationClient.getReadOnlyBookies()); - fail("Should fail to get writable bookies"); - } catch (ZKException zke) { - // expected to throw zookeeper exception - } - } - - @Test - public void testWatchWritableBookiesSuccess() throws Exception { - testWatchBookiesSuccess(true); - } - - @Test - public void testWatchReadonlyBookiesSuccess() throws Exception { - testWatchBookiesSuccess(false); - } - - @SuppressWarnings("unchecked") - private void testWatchBookiesSuccess(boolean isWritable) - throws Exception { - // - // 1. test watch bookies with a listener - // - - LinkedBlockingQueue>> updates = - spy(new LinkedBlockingQueue<>()); - RegistrationListener listener = bookies -> { - try { - updates.put(bookies); - } catch (InterruptedException e) { - log.warn("Interrupted on enqueue bookie updates", e); - } - }; - - Set addresses = prepareNBookies(10); - List children = Lists.newArrayList(); - for (BookieId address : addresses) { - children.add(address.toString()); - prepareReadBookieServiceInfo(address, !isWritable); - } - Stat stat = mock(Stat.class); - when(stat.getCversion()).thenReturn(1234); - - mockGetChildren( - isWritable ? regPath : regReadonlyPath, - true, - Code.OK.intValue(), children, stat); - - if (isWritable) { - result(zkRegistrationClient.watchWritableBookies(listener)); - } else { - result(zkRegistrationClient.watchReadOnlyBookies(listener)); - } - - Versioned> update = updates.take(); - verify(updates, times(1)).put(any(Versioned.class)); - assertEquals(new LongVersion(1234), update.getVersion()); - assertSetEquals( - addresses, update.getValue()); - - verify(mockZk, times(1)) - .getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any()); - - // - // 2. test watch bookies with a second listener. the second listener returns cached bookies - // without calling `getChildren` again - // - - // register another listener - LinkedBlockingQueue>> secondUpdates = - spy(new LinkedBlockingQueue<>()); - RegistrationListener secondListener = bookies -> { - try { - secondUpdates.put(bookies); - } catch (InterruptedException e) { - log.warn("Interrupted on enqueue bookie updates", e); - } - }; - if (isWritable) { - result(zkRegistrationClient.watchWritableBookies(secondListener)); - } else { - result(zkRegistrationClient.watchReadOnlyBookies(secondListener)); - } - Versioned> secondListenerUpdate = secondUpdates.take(); - // first listener will not be notified with any update - verify(updates, times(1)).put(any(Versioned.class)); - // second listener will receive same update as the first listener received before - verify(secondUpdates, times(1)).put(any(Versioned.class)); - assertSame(update.getVersion(), secondListenerUpdate.getVersion()); - assertSame(update.getValue(), secondListenerUpdate.getValue()); - - // the second listener will return the cached value without issuing another getChildren call - verify(mockZk, times(1)) - .getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any()); - - // - // 3. simulate session expire, it will trigger watcher to refetch bookies again. - // but since there is no updates on bookies, the registered listeners will not be notified. - // - - notifyWatchedEvent( - EventType.None, - KeeperState.Expired, - isWritable ? regPath : regReadonlyPath); - - // if session expires, the watcher task will get into backoff state - controller.advance(Duration.ofMillis(ZK_CONNECT_BACKOFF_MS)); - - // the same updates returns, the getChildren calls increase to 2 - // but since there is no updates, so no notification is sent. - verify(mockZk, times(2)) - .getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any()); - assertNull(updates.poll()); - // both listener and secondListener will not receive any old update - verify(updates, times(1)).put(any(Versioned.class)); - verify(secondUpdates, times(1)).put(any(Versioned.class)); - - // - // 4. notify with new bookies. both listeners will be notified with new bookies. - // - - Set newAddresses = prepareNBookies(20); - List newChildren = Lists.newArrayList(); - for (BookieId address : newAddresses) { - newChildren.add(address.toString()); - prepareReadBookieServiceInfo(address, !isWritable); - } - Stat newStat = mock(Stat.class); - when(newStat.getCversion()).thenReturn(1235); - - mockGetChildren( - isWritable ? regPath : regReadonlyPath, - true, - Code.OK.intValue(), newChildren, newStat); - - // trigger watcher - notifyWatchedEvent( - EventType.NodeChildrenChanged, - KeeperState.SyncConnected, - isWritable ? regPath : regReadonlyPath); - - update = updates.take(); - assertEquals(new LongVersion(1235), update.getVersion()); - assertSetEquals( - newAddresses, update.getValue()); - secondListenerUpdate = secondUpdates.take(); - assertSame(update.getVersion(), secondListenerUpdate.getVersion()); - assertSame(update.getValue(), secondListenerUpdate.getValue()); - - verify(mockZk, times(3)) - .getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any()); - verify(updates, times(2)).put(any(Versioned.class)); - verify(secondUpdates, times(2)).put(any(Versioned.class)); - - // - // 5. unwatch the second listener and notify with new bookies again. only first listener will - // be notified with new bookies. - // - - newAddresses = prepareNBookies(25); - newChildren.clear(); - newChildren = Lists.newArrayList(); - for (BookieId address : newAddresses) { - newChildren.add(address.toString()); - prepareReadBookieServiceInfo(address, !isWritable); - } - newStat = mock(Stat.class); - when(newStat.getCversion()).thenReturn(1236); - - mockGetChildren( - isWritable ? regPath : regReadonlyPath, - true, - Code.OK.intValue(), newChildren, newStat); - - if (isWritable) { - assertEquals(2, zkRegistrationClient.getWatchWritableBookiesTask().getNumListeners()); - zkRegistrationClient.unwatchWritableBookies(secondListener); - assertEquals(1, zkRegistrationClient.getWatchWritableBookiesTask().getNumListeners()); - } else { - assertEquals(2, zkRegistrationClient.getWatchReadOnlyBookiesTask().getNumListeners()); - zkRegistrationClient.unwatchReadOnlyBookies(secondListener); - assertEquals(1, zkRegistrationClient.getWatchReadOnlyBookiesTask().getNumListeners()); - } - - // trigger watcher - notifyWatchedEvent( - EventType.NodeChildrenChanged, - KeeperState.SyncConnected, - isWritable ? regPath : regReadonlyPath); - - update = updates.take(); - assertEquals(new LongVersion(1236), update.getVersion()); - assertSetEquals( - newAddresses, update.getValue()); - secondListenerUpdate = secondUpdates.poll(); - assertNull(secondListenerUpdate); - - verify(mockZk, times(4)) - .getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any()); - verify(updates, times(3)).put(any(Versioned.class)); - verify(secondUpdates, times(2)).put(any(Versioned.class)); - - // - // 6. unwatch the first listener. the watch task will be closed and zk watcher will be removed. - // - // - - WatchTask expectedWatcher; - if (isWritable) { - expectedWatcher = zkRegistrationClient.getWatchWritableBookiesTask(); - assertFalse(expectedWatcher.isClosed()); - zkRegistrationClient.unwatchWritableBookies(listener); - assertNull(zkRegistrationClient.getWatchWritableBookiesTask()); - } else { - expectedWatcher = zkRegistrationClient.getWatchReadOnlyBookiesTask(); - assertFalse(expectedWatcher.isClosed()); - zkRegistrationClient.unwatchReadOnlyBookies(listener); - assertNull(zkRegistrationClient.getWatchReadOnlyBookiesTask()); - } - // the watch task will not be closed since there is still a listener - assertTrue(expectedWatcher.isClosed()); - } - - @Test - public void testWatchWritableBookiesTwice() throws Exception { - testWatchBookiesTwice(true); - } - - @Test - public void testWatchReadonlyBookiesTwice() throws Exception { - testWatchBookiesTwice(false); - } - - private void testWatchBookiesTwice(boolean isWritable) - throws Exception { - int zkCallbackDelayMs = 100; - - Set addresses = prepareNBookies(10); - List children = Lists.newArrayList(); - for (BookieId address : addresses) { - children.add(address.toString()); - prepareReadBookieServiceInfo(address, !isWritable); - } - Stat stat = mock(Stat.class); - when(stat.getCversion()).thenReturn(1234); - - mockGetChildren( - isWritable ? regPath : regReadonlyPath, - true, - Code.OK.intValue(), children, stat, zkCallbackDelayMs); - - CompletableFuture>> firstResult = new CompletableFuture<>(); - RegistrationListener firstListener = bookies -> firstResult.complete(bookies); - - CompletableFuture>> secondResult = new CompletableFuture<>(); - RegistrationListener secondListener = bookies -> secondResult.complete(bookies); - - List> watchFutures = Lists.newArrayListWithExpectedSize(2); - if (isWritable) { - watchFutures.add(zkRegistrationClient.watchWritableBookies(firstListener)); - watchFutures.add(zkRegistrationClient.watchWritableBookies(secondListener)); - } else { - watchFutures.add(zkRegistrationClient.watchReadOnlyBookies(firstListener)); - watchFutures.add(zkRegistrationClient.watchReadOnlyBookies(secondListener)); - } - - // trigger zkCallbackExecutor to execute getChildren callback - zkCallbackController.advance(Duration.ofMillis(zkCallbackDelayMs)); - - result(collect(watchFutures)); - assertEquals(firstResult.get().getVersion(), secondResult.get().getVersion()); - assertSetEquals(firstResult.get().getValue(), secondResult.get().getValue()); - } - - @Test - public void testWatchWritableBookiesFailure() throws Exception { - testWatchBookiesFailure(true); - } - - @Test - public void testWatchReadonlyBookiesFailure() throws Exception { - testWatchBookiesFailure(false); - } - - private void testWatchBookiesFailure(boolean isWritable) - throws Exception { - int zkCallbackDelayMs = 100; - - mockGetChildren( - isWritable ? regPath : regReadonlyPath, - true, - Code.NONODE.intValue(), null, null, zkCallbackDelayMs); - - CompletableFuture>> listenerResult = new CompletableFuture<>(); - RegistrationListener listener = bookies -> listenerResult.complete(bookies); - - CompletableFuture watchFuture; - - WatchTask watchTask; - if (isWritable) { - watchFuture = zkRegistrationClient.watchWritableBookies(listener); - watchTask = zkRegistrationClient.getWatchWritableBookiesTask(); - } else { - watchFuture = zkRegistrationClient.watchReadOnlyBookies(listener); - watchTask = zkRegistrationClient.getWatchReadOnlyBookiesTask(); - } - assertNotNull(watchTask); - assertEquals(1, watchTask.getNumListeners()); - - // trigger zkCallbackExecutor to execute getChildren callback - zkCallbackController.advance(Duration.ofMillis(zkCallbackDelayMs)); - - try { - result(watchFuture); - fail("Should fail to watch writable bookies if reg path doesn't exist"); - } catch (ZKException zke) { - // expected - } - assertEquals(0, watchTask.getNumListeners()); - assertTrue(watchTask.isClosed()); - if (isWritable) { - assertNull(zkRegistrationClient.getWatchWritableBookiesTask()); - } else { - assertNull(zkRegistrationClient.getWatchReadOnlyBookiesTask()); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/BookieServiceInfoTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/BookieServiceInfoTest.java deleted file mode 100644 index 4173d630002..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/BookieServiceInfoTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2020 The Apache Software Foundation. - * - * Licensed 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. - */ -package org.apache.bookkeeper.discover; - -import static org.apache.bookkeeper.discover.ZKRegistrationClient.deserializeBookieServiceInfo; -import static org.apache.bookkeeper.discover.ZKRegistrationManager.serializeBookieServiceInfo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import org.apache.bookkeeper.discover.BookieServiceInfo.Endpoint; -import org.apache.bookkeeper.net.BookieId; -import org.junit.Test; - -/** - * Unit test of the {@link BookieServiceInfo} serialization/deserialization methods. - */ -public class BookieServiceInfoTest { - - @Test - public void testSerializeDeserializeBookieServiceInfo() throws Exception { - String bookieId = "127.0.0.1:3181"; - { - BookieServiceInfo expected = new BookieServiceInfo(); - Endpoint endpointRPC = new Endpoint("1", 1281, "localhost", "bookie-rpc", - Collections.emptyList(), Collections.emptyList()); - Endpoint endpointHTTP = new Endpoint("2", 1281, "localhost", "bookie-http", - Collections.emptyList(), Collections.emptyList()); - expected.setEndpoints(Arrays.asList(endpointRPC, endpointHTTP)); - - Map properties = new HashMap<>(); - properties.put("test", "value"); - expected.setProperties(properties); - - byte[] serialized = serializeBookieServiceInfo(expected); - BookieServiceInfo deserialized = deserializeBookieServiceInfo(BookieId.parse(bookieId), serialized); - - assertBookieServiceInfoEquals(expected, deserialized); - } - } - - @Test - public void testDeserializeBookieServiceInfo() throws Exception { - BookieId bookieId = BookieId.parse("127.0.0.1:3181"); - { - BookieServiceInfo expected = BookieServiceInfoUtils.buildLegacyBookieServiceInfo(bookieId.toString()); - BookieServiceInfo deserialized = deserializeBookieServiceInfo(bookieId, null); - - assertBookieServiceInfoEquals(expected, deserialized); - } - { - BookieServiceInfo expected = BookieServiceInfoUtils.buildLegacyBookieServiceInfo(bookieId.toString()); - BookieServiceInfo deserialized = deserializeBookieServiceInfo(bookieId, new byte[]{}); - - assertBookieServiceInfoEquals(expected, deserialized); - } - } - - private void assertBookieServiceInfoEquals(BookieServiceInfo expected, BookieServiceInfo provided) { - for (Endpoint ep : expected.getEndpoints()) { - Endpoint e = provided.getEndpoints().stream() - .filter(ee -> Objects.equals(ee.getId(), ep.getId())) - .findFirst() - .get(); - assertThat(e.getHost(), is(ep.getHost())); - assertThat(e.getPort(), is(ep.getPort())); - assertThat(e.getProtocol(), is(ep.getProtocol())); - assertArrayEquals(e.getAuth().toArray(), ep.getAuth().toArray()); - assertArrayEquals(e.getExtensions().toArray(), ep.getExtensions().toArray()); - } - assertEquals(expected.getProperties(), provided.getProperties()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationClient.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationClient.java deleted file mode 100644 index 74455f9a897..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationClient.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.discover; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; - -/** - * Mock implementation of registration client. - * All actions take place in a single thread executor, so they are async - * w.r.t. the caller. - */ -public class MockRegistrationClient implements RegistrationClient { - final ExecutorService executor; - private long currentVersion = 0; - private Set bookies = new HashSet(); - private Set allBookies = new HashSet(); - private Set readOnlyBookies = new HashSet(); - private Set bookieWatchers = new HashSet(); - private Set readOnlyBookieWatchers = new HashSet(); - - public MockRegistrationClient() { - this.executor = Executors.newSingleThreadExecutor((r) -> new Thread(r, "MockRegistrationClient")); - } - - @Override - public void close() { - executor.shutdownNow(); - } - - private static Versioned> versioned(Set bookies, long version) { - return new Versioned<>(Collections.unmodifiableSet(bookies), new LongVersion(version)); - } - - public CompletableFuture addBookies(BookieId... bookies) { - CompletableFuture promise = new CompletableFuture<>(); - executor.submit(() -> { - currentVersion++; - Collections.addAll(this.bookies, bookies); - bookieWatchers.forEach(w -> w.onBookiesChanged(versioned(this.bookies, currentVersion))); - promise.complete(null); - }); - return promise; - } - - public CompletableFuture removeBookies(BookieId... bookies) { - CompletableFuture promise = new CompletableFuture<>(); - executor.submit(() -> { - currentVersion++; - this.bookies.addAll(Arrays.asList(bookies)); - bookieWatchers.forEach(w -> w.onBookiesChanged(versioned(this.bookies, currentVersion))); - promise.complete(null); - }); - return promise; - } - - public CompletableFuture addReadOnlyBookies(BookieId... bookies) { - CompletableFuture promise = new CompletableFuture<>(); - executor.submit(() -> { - currentVersion++; - this.readOnlyBookies.addAll(Arrays.asList(bookies)); - readOnlyBookieWatchers.forEach(w -> w.onBookiesChanged(versioned(readOnlyBookies, currentVersion))); - promise.complete(null); - }); - return promise; - } - - public CompletableFuture removeReadOnlyBookies(BookieId... bookies) { - CompletableFuture promise = new CompletableFuture<>(); - executor.submit(() -> { - currentVersion++; - this.readOnlyBookies.addAll(Arrays.asList(bookies)); - readOnlyBookieWatchers.forEach(w -> w.onBookiesChanged(versioned(readOnlyBookies, currentVersion))); - promise.complete(null); - }); - return promise; - } - - @Override - public CompletableFuture>> getWritableBookies() { - CompletableFuture>> promise = new CompletableFuture<>(); - executor.submit(() -> promise.complete(versioned(bookies, currentVersion))); - return promise; - } - - @Override - public CompletableFuture>> getAllBookies() { - CompletableFuture>> promise = new CompletableFuture<>(); - executor.submit(() -> promise.complete(versioned(allBookies, currentVersion))); - return promise; - } - - @Override - public CompletableFuture>> getReadOnlyBookies() { - CompletableFuture>> promise = new CompletableFuture<>(); - executor.submit(() -> promise.complete(versioned(readOnlyBookies, currentVersion))); - return promise; - } - - @Override - public CompletableFuture watchWritableBookies(RegistrationListener listener) { - CompletableFuture promise = new CompletableFuture<>(); - executor.submit(() -> { - bookieWatchers.add(listener); - promise.complete(null); - }); - return promise; - } - - @Override - public void unwatchWritableBookies(RegistrationListener listener) { - executor.submit(() -> { - bookieWatchers.remove(listener); - }); - } - - @Override - public CompletableFuture watchReadOnlyBookies(RegistrationListener listener) { - CompletableFuture promise = new CompletableFuture<>(); - executor.submit(() -> { - readOnlyBookieWatchers.add(listener); - promise.complete(null); - }); - return promise; - } - - @Override - public void unwatchReadOnlyBookies(RegistrationListener listener) { - executor.submit(() -> { - readOnlyBookieWatchers.remove(listener); - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationManager.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationManager.java deleted file mode 100644 index 44631018b29..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationManager.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.discover; - -import java.util.concurrent.ConcurrentHashMap; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; - -/** - * Mock implementation of RegistrationManager. - */ -public class MockRegistrationManager implements RegistrationManager { - private final ConcurrentHashMap> cookies = new ConcurrentHashMap<>(); - - @Override - public void close() {} - - @Override - public String getClusterInstanceId() throws BookieException { - return "mock-cluster"; - } - - @Override - public void registerBookie(BookieId bookieId, boolean readOnly, - BookieServiceInfo serviceInfo) throws BookieException { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } - - @Override - public void unregisterBookie(BookieId bookieId, boolean readOnly) throws BookieException { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } - - @Override - public boolean isBookieRegistered(BookieId bookieId) throws BookieException { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } - - @Override - public void writeCookie(BookieId bookieId, Versioned cookieData) throws BookieException { - try { - cookies.compute(bookieId, (bookieId1, current) -> { - if (cookieData.getVersion() == Version.NEW) { - if (current == null) { - return new Versioned(cookieData.getValue(), new LongVersion(1)); - } else { - throw new RuntimeException(new BookieException.CookieExistException(bookieId.getId())); - } - } else { - if (current != null - && cookieData.getVersion().equals(current.getVersion())) { - LongVersion oldVersion = (LongVersion) current.getVersion(); - LongVersion newVersion = new LongVersion(oldVersion.getLongVersion() + 1); - return new Versioned(cookieData.getValue(), newVersion); - } else { - throw new RuntimeException(new BookieException.CookieExistException(bookieId.getId())); - } - } - }); - } catch (RuntimeException e) { - if (e.getCause() instanceof BookieException) { - throw (BookieException) e.getCause(); - } - } - } - - @Override - public Versioned readCookie(BookieId bookieId) throws BookieException { - Versioned cookie = cookies.get(bookieId); - if (cookie == null) { - throw new BookieException.CookieNotFoundException(bookieId.toString()); - } - return cookie; - } - - @Override - public void removeCookie(BookieId bookieId, Version version) throws BookieException { - try { - cookies.compute(bookieId, (bookieId1, current) -> { - if (current == null) { - throw new RuntimeException(new BookieException.CookieNotFoundException(bookieId.toString())); - } else if (current.getVersion().equals(version)) { - return null; - } else { - throw new RuntimeException(new BookieException.MetadataStoreException("Bad version")); - } - }); - } catch (RuntimeException e) { - if (e.getCause() instanceof BookieException) { - throw (BookieException) e.getCause(); - } - } - - } - - @Override - public boolean prepareFormat() throws Exception { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } - - @Override - public boolean initNewCluster() throws Exception { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } - - @Override - public boolean format() throws Exception { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } - - @Override - public boolean nukeExistingCluster() throws Exception { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } - - @Override - public void addRegistrationListener(RegistrationListener listener) { - throw new UnsupportedOperationException("Not implemented in mock. Implement if you need it"); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithBookieAddressTracking.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithBookieAddressTracking.java deleted file mode 100644 index f9b6de342c2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithBookieAddressTracking.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.discover; - -/** - * Unit test of {@link RegistrationClient} with Bookie Address Tracking feature. - */ -public class TestZkRegistrationClientWithBookieAddressTracking extends AbstractTestZkRegistrationClient { - - public TestZkRegistrationClientWithBookieAddressTracking() { - super(true); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithoutBookieAddressTracking.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithoutBookieAddressTracking.java deleted file mode 100644 index 39ed8eacc81..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithoutBookieAddressTracking.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - - -package org.apache.bookkeeper.discover; - -/** - * Unit test of {@link RegistrationClient} without Bookie Address Tracking feature. - */ -public class TestZkRegistrationClientWithoutBookieAddressTracking extends AbstractTestZkRegistrationClient { - - public TestZkRegistrationClientWithoutBookieAddressTracking() { - super(false); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationManager.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationManager.java deleted file mode 100644 index 4e1b06ba220..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationManager.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.discover; - -import static org.junit.Assert.assertNotNull; - -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.test.ZooKeeperCluster; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link RegistrationManager}. - */ -public class TestZkRegistrationManager { - - private ZooKeeperCluster localZkServer; - private ZooKeeper zkc; - - @Before - public void setup() throws Exception { - localZkServer = new ZooKeeperUtil(); - localZkServer.startCluster(); - } - - @After - public void teardown() throws Exception { - localZkServer.stopCluster(); - } - - @Test - public void testPrepareFormat () throws Exception { - try { - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri("zk+hierarchical://localhost:2181/test/ledgers"); - zkc = localZkServer.getZooKeeperClient(); - ZKRegistrationManager zkRegistrationManager = new ZKRegistrationManager(conf, zkc); - zkRegistrationManager.prepareFormat(); - assertNotNull(zkc.exists("/test/ledgers", false)); - } finally { - if (zkc != null) { - zkc.close(); - } - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/AbstractZkLedgerManagerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/AbstractZkLedgerManagerTest.java deleted file mode 100644 index 8e53f2088d1..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/AbstractZkLedgerManagerTest.java +++ /dev/null @@ -1,848 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.apache.bookkeeper.meta.AbstractZkLedgerManager.ZK_CONNECT_BACKOFF_MS; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.withSettings; - -import com.google.common.collect.Lists; -import java.time.Duration; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.testing.executors.MockExecutorController; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.LedgerMetadataListener; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.bookkeeper.zookeeper.MockZooKeeperTestCase; -import org.apache.zookeeper.AsyncCallback.DataCallback; -import org.apache.zookeeper.AsyncCallback.StatCallback; -import org.apache.zookeeper.AsyncCallback.VoidCallback; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test of {@link AbstractZkLedgerManager}. - */ -@RunWith(MockitoJUnitRunner.Silent.class) -public class AbstractZkLedgerManagerTest extends MockZooKeeperTestCase { - - private ClientConfiguration conf; - private AbstractZkLedgerManager ledgerManager; - private ScheduledExecutorService scheduler; - private MockExecutorController schedulerController; - private LedgerMetadata metadata; - private LedgerMetadataSerDe serDe; - private MockedStatic executorsMockedStatic; - - @Before - public void setup() throws Exception { - executorsMockedStatic = mockStatic(Executors.class, CALLS_REAL_METHODS); - - super.setup(); - - this.scheduler = mock(ScheduledExecutorService.class); - this.schedulerController = new MockExecutorController() - .controlSubmit(scheduler) - .controlSchedule(scheduler) - .controlExecute(scheduler) - .controlScheduleAtFixedRate(scheduler, 10); - - executorsMockedStatic.when(() -> Executors.newSingleThreadScheduledExecutor(any())).thenReturn(scheduler); - - this.conf = new ClientConfiguration(); - this.ledgerManager = mock( - AbstractZkLedgerManager.class, - withSettings() - .useConstructor(conf, mockZk) - .defaultAnswer(CALLS_REAL_METHODS)); - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 3181).toBookieId(), - new BookieSocketAddress("192.0.2.2", 3181).toBookieId(), - new BookieSocketAddress("192.0.2.3", 3181).toBookieId(), - new BookieSocketAddress("192.0.2.4", 3181).toBookieId(), - new BookieSocketAddress("192.0.2.5", 3181).toBookieId()); - this.metadata = LedgerMetadataBuilder.create() - .withId(123L) - .withDigestType(DigestType.CRC32C).withPassword(new byte[0]) - .withEnsembleSize(5) - .withWriteQuorumSize(3) - .withAckQuorumSize(3) - .newEnsembleEntry(0L, ensemble) - .withCreationTime(12345L).build(); - - doAnswer(invocationOnMock -> { - long ledgerId = invocationOnMock.getArgument(0); - return String.valueOf(ledgerId); - }).when(ledgerManager).getLedgerPath(anyLong()); - doAnswer(invocationOnMock -> { - String ledgerStr = invocationOnMock.getArgument(0); - return Long.parseLong(ledgerStr); - }).when(ledgerManager).getLedgerId(anyString()); - - // verify constructor - assertEquals(ZKMetadataDriverBase.resolveZkLedgersRootPath(conf), ledgerManager.ledgerRootPath); - assertSame(mockZk, ledgerManager.zk); - assertSame(conf, ledgerManager.conf); - assertSame(scheduler, ledgerManager.scheduler); - - this.serDe = new LedgerMetadataSerDe(); - } - - @After - public void teardown() throws Exception { - super.teardown(); - - executorsMockedStatic.close(); - - if (null != ledgerManager) { - ledgerManager.close(); - - // zookeeper is passed in, it should not be closed. - verify(mockZk, times(0)).close(); - verify(scheduler, times(1)).shutdown(); - } - } - - @Test - public void testCreateLedgerMetadataSuccess() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - mockZkUtilsAsyncCreateFullPathOptimistic( - ledgerStr, CreateMode.PERSISTENT, - KeeperException.Code.OK.intValue(), ledgerStr - ); - - Versioned result = ledgerManager.createLedgerMetadata(ledgerId, metadata).get(); - - assertEquals(new LongVersion(0), result.getVersion()); - } - - @Test - public void testCreateLedgerMetadataNodeExists() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - mockZkUtilsAsyncCreateFullPathOptimistic( - ledgerStr, CreateMode.PERSISTENT, - KeeperException.Code.NODEEXISTS.intValue(), null); - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - /* - * this is needed because in AbstractZkLedgerManager.readLedgerMetadata - * if MetadataFormatVersion is >2, then for createLedgerMetadata if we - * get NODEEXISTS exception then it will try to read to make sure ledger - * creation is robust to ZK connection loss. Please check Issue #1967. - */ - mockZkGetData( - ledgerStr, false, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - try { - result(ledgerManager.createLedgerMetadata(ledgerId, metadata)); - fail("Should fail to create ledger metadata if the ledger already exists"); - } catch (Exception e) { - assertTrue(e instanceof BKException); - BKException bke = (BKException) e; - assertEquals(Code.LedgerExistException, bke.getCode()); - } - } - - @Test - public void testCreateLedgerMetadataException() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - mockZkUtilsAsyncCreateFullPathOptimistic( - ledgerStr, CreateMode.PERSISTENT, - KeeperException.Code.CONNECTIONLOSS.intValue(), null); - - try { - result(ledgerManager.createLedgerMetadata(ledgerId, metadata)); - fail("Should fail to create ledger metadata when encountering zookeeper exception"); - } catch (Exception e) { - assertTrue(e instanceof BKException); - BKException bke = (BKException) e; - assertEquals(Code.ZKException, bke.getCode()); - assertTrue(bke.getCause() instanceof KeeperException); - } - } - - @Test - public void testRemoveLedgerMetadataSuccess() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - LongVersion version = new LongVersion(1234L); - - mockZkDelete( - ledgerStr, (int) version.getLongVersion(), - KeeperException.Code.OK.intValue()); - - ledgerManager.removeLedgerMetadata(ledgerId, version).get(); - - verify(mockZk, times(1)) - .delete(eq(ledgerStr), eq(1234), any(VoidCallback.class), eq(null)); - } - - @Test - public void testRemoveLedgerMetadataVersionAny() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - mockZkDelete( - ledgerStr, -1, - KeeperException.Code.OK.intValue()); - - ledgerManager.removeLedgerMetadata(ledgerId, Version.ANY).get(); - - verify(mockZk, times(1)) - .delete(eq(ledgerStr), eq(-1), any(VoidCallback.class), eq(null)); - } - - @Test - public void testRemoveLedgerMetadataVersionNew() throws Exception { - testRemoveLedgerMetadataInvalidVersion(Version.NEW); - } - - @Test - public void testRemoveLedgerMetadataUnknownVersionType() throws Exception { - Version version = mock(Version.class); - testRemoveLedgerMetadataInvalidVersion(version); - } - - private void testRemoveLedgerMetadataInvalidVersion(Version version) throws Exception { - long ledgerId = System.currentTimeMillis(); - - try { - result(ledgerManager.removeLedgerMetadata(ledgerId, version)); - fail("Should fail to remove metadata if version is " + Version.NEW); - } catch (BKException bke) { - assertEquals(Code.MetadataVersionException, bke.getCode()); - } - } - - @Test - public void testRemoveLedgerMetadataNoNode() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - LongVersion version = new LongVersion(1234L); - - mockZkDelete( - ledgerStr, (int) version.getLongVersion(), - KeeperException.Code.NONODE.intValue()); - - try { - result(ledgerManager.removeLedgerMetadata(ledgerId, version)); - } catch (BKException bke) { - fail("Should succeed"); - } - - verify(mockZk, times(1)) - .delete(eq(ledgerStr), eq(1234), any(VoidCallback.class), eq(null)); - } - - @Test - public void testRemoveLedgerMetadataException() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - LongVersion version = new LongVersion(1234L); - - mockZkDelete( - ledgerStr, (int) version.getLongVersion(), - KeeperException.Code.CONNECTIONLOSS.intValue()); - - try { - result(ledgerManager.removeLedgerMetadata(ledgerId, version)); - fail("Should fail to remove metadata upon ZKException"); - } catch (BKException bke) { - assertEquals(Code.ZKException, bke.getCode()); - } - - verify(mockZk, times(1)) - .delete(eq(ledgerStr), eq(1234), any(VoidCallback.class), eq(null)); - } - - @Test - public void testRemoveLedgerMetadataHierarchical() throws Exception { - HierarchicalLedgerManager hlm = new HierarchicalLedgerManager(conf, mockZk); - testRemoveLedgerMetadataHierarchicalLedgerManager(hlm); - } - - @Test - public void testRemoveLedgerMetadataLongHierarchical() throws Exception { - LongHierarchicalLedgerManager hlm = new LongHierarchicalLedgerManager(conf, mockZk); - testRemoveLedgerMetadataHierarchicalLedgerManager(hlm); - } - - private void testRemoveLedgerMetadataHierarchicalLedgerManager(AbstractZkLedgerManager lm) throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = lm.getLedgerPath(ledgerId); - LongVersion version = new LongVersion(1234L); - - mockZkUtilsAsyncDeleteFullPathOptimistic( - ledgerStr, (int) version.getLongVersion(), - KeeperException.Code.OK.intValue()); - - lm.removeLedgerMetadata(ledgerId, version).get(); - - ZkUtils.asyncDeleteFullPathOptimistic( - eq(mockZk), eq(ledgerStr), eq(1234), any(VoidCallback.class), eq(ledgerStr)); - - } - - @Test - public void testReadLedgerMetadataSuccess() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkGetData( - ledgerStr, false, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - Versioned readMetadata = result(ledgerManager.readLedgerMetadata(ledgerId)); - assertEquals(metadata, readMetadata.getValue()); - assertEquals(new LongVersion(1234), readMetadata.getVersion()); - - verify(mockZk, times(1)) - .getData(eq(ledgerStr), eq(null), any(DataCallback.class), any()); - } - - @Test - public void testReadLedgerMetadataNoNode() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - mockZkGetData( - ledgerStr, false, - KeeperException.Code.NONODE.intValue(), null, null); - - try { - result(ledgerManager.readLedgerMetadata(ledgerId)); - fail("Should fail on reading ledger metadata if a ledger doesn't exist"); - } catch (BKException bke) { - assertEquals(Code.NoSuchLedgerExistsOnMetadataServerException, bke.getCode()); - } - - verify(mockZk, times(1)) - .getData(eq(ledgerStr), eq(null), any(DataCallback.class), any()); - } - - @Test - public void testReadLedgerMetadataException() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - mockZkGetData( - ledgerStr, false, - KeeperException.Code.CONNECTIONLOSS.intValue(), null, null); - - try { - result(ledgerManager.readLedgerMetadata(ledgerId)); - fail("Should fail on reading ledger metadata if a ledger doesn't exist"); - } catch (BKException bke) { - assertEquals(Code.ZKException, bke.getCode()); - } - - verify(mockZk, times(1)) - .getData(eq(ledgerStr), eq(null), any(DataCallback.class), any()); - } - - @Test - public void testReadLedgerMetadataStatMissing() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - mockZkGetData( - ledgerStr, false, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), null); - - try { - result(ledgerManager.readLedgerMetadata(ledgerId)); - fail("Should fail on reading ledger metadata if a ledger doesn't exist"); - } catch (BKException bke) { - assertEquals(Code.ZKException, bke.getCode()); - } - - verify(mockZk, times(1)) - .getData(eq(ledgerStr), eq(null), any(DataCallback.class), any()); - } - - @Test - public void testReadLedgerMetadataDataCorrupted() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkGetData( - ledgerStr, false, - KeeperException.Code.OK.intValue(), new byte[0], stat); - - try { - result(ledgerManager.readLedgerMetadata(ledgerId)); - fail("Should fail on reading ledger metadata if a ledger doesn't exist"); - } catch (BKException bke) { - assertEquals(Code.ZKException, bke.getCode()); - } - - verify(mockZk, times(1)) - .getData(eq(ledgerStr), eq(null), any(DataCallback.class), any()); - } - - @Test - public void testWriteLedgerMetadataSuccess() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1235); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkSetData( - ledgerStr, serDe.serialize(metadata), 1234, - KeeperException.Code.OK.intValue(), stat); - - Version v = ledgerManager.writeLedgerMetadata(ledgerId, metadata, new LongVersion(1234L)).get().getVersion(); - - assertEquals(new LongVersion(1235L), v); - - verify(mockZk, times(1)) - .setData(eq(ledgerStr), any(byte[].class), eq(1234), any(StatCallback.class), any()); - } - - @Test - public void testWriteLedgerMetadataBadVersion() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - mockZkSetData( - ledgerStr, serDe.serialize(metadata), 1234, - KeeperException.Code.BADVERSION.intValue(), null); - - try { - result(ledgerManager.writeLedgerMetadata(ledgerId, metadata, new LongVersion(1234L))); - fail("Should fail on writing ledger metadata if encountering bad version"); - } catch (BKException bke) { - assertEquals(Code.MetadataVersionException, bke.getCode()); - } - - verify(mockZk, times(1)) - .setData(eq(ledgerStr), any(byte[].class), eq(1234), any(StatCallback.class), any()); - } - - @Test - public void testWriteLedgerMetadataException() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - mockZkSetData( - ledgerStr, serDe.serialize(metadata), 1234, - KeeperException.Code.CONNECTIONLOSS.intValue(), null); - - try { - result(ledgerManager.writeLedgerMetadata(ledgerId, metadata, new LongVersion(1234L))); - fail("Should fail on writing ledger metadata if encountering zookeeper exceptions"); - } catch (BKException bke) { - assertEquals(Code.ZKException, bke.getCode()); - } - - - verify(mockZk, times(1)) - .setData(eq(ledgerStr), any(byte[].class), eq(1234), any(StatCallback.class), any()); - } - - @Test - public void testWriteLedgerMetadataInvalidVersion() throws Exception { - Version[] versions = new Version[] { - Version.NEW, - Version.ANY, - mock(Version.class) - }; - for (Version version : versions) { - testWriteLedgerMetadataInvalidVersion(version); - } - } - - private void testWriteLedgerMetadataInvalidVersion(Version invalidVersion) throws Exception { - long ledgerId = System.currentTimeMillis(); - - try { - result(ledgerManager.writeLedgerMetadata(ledgerId, metadata, invalidVersion)); - fail("Should fail on writing ledger metadata if an invalid version is provided."); - } catch (BKException bke) { - assertEquals(Code.MetadataVersionException, bke.getCode()); - } - - verify(mockZk, times(0)) - .setData(anyString(), any(byte[].class), anyInt(), any(StatCallback.class), any()); - } - - @Test - public void testLedgerMetadataListener() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - LinkedBlockingQueue changes = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener = (ledgerId1, metadata) -> changes.add(metadata.getValue()); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - ledgerManager.registerLedgerMetadataListener(ledgerId, listener); - - // the listener will be notified with first get - LedgerMetadata change1 = changes.take(); - assertEquals(metadata, change1); - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // the watcher is registered for receiving watched event - assertTrue(watchers.containsKey(ledgerStr)); - Set watcherSet1 = watchers.get(ledgerStr); - assertEquals(1, watcherSet1.size()); - Watcher registeredWatcher1 = watcherSet1.stream().findFirst().get(); - - // mock get data to return an updated metadata - when(stat.getVersion()).thenReturn(1235); - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - // notify the watcher event - notifyWatchedEvent( - EventType.NodeDataChanged, KeeperState.SyncConnected, ledgerStr); - - // the listener should receive an updated metadata - LedgerMetadata change2 = changes.take(); - assertEquals(metadata, change2); - verify(mockZk, times(2)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // after the listener receive an updated metadata, a new watcher should be registered - // for subsequent changes again. - assertTrue(watchers.containsKey(ledgerStr)); - Set watcherSet2 = watchers.get(ledgerStr); - assertEquals(1, watcherSet2.size()); - Watcher registeredWatcher2 = watcherSet2.stream().findFirst().get(); - - // zookeeper watchers are same, since there is only one giant watcher per ledger manager. - assertSame(registeredWatcher1, registeredWatcher2); - - // verify scheduler - verify(scheduler, times(2)).submit(any(Runnable.class)); - verify(scheduler, times(0)) - .schedule(any(Runnable.class), anyLong(), any(TimeUnit.class)); - } - - @Test - public void testLedgerMetadataListenerOnLedgerDeleted() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - LinkedBlockingQueue> changes = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener = - (ledgerId1, metadata) -> changes.add(Optional.ofNullable(metadata != null ? metadata.getValue() : null)); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - ledgerManager.registerLedgerMetadataListener(ledgerId, listener); - assertTrue(ledgerManager.listeners.containsKey(ledgerId)); - - // the listener will be notified with first get - LedgerMetadata change1 = changes.take().get(); - assertEquals(metadata, change1); - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // the watcher is registered for receiving watched event - assertTrue(watchers.containsKey(ledgerStr)); - - // mock get data to simulate an ledger is deleted - mockZkGetData( - ledgerStr, true, - KeeperException.Code.NONODE.intValue(), null, null); - - // notify the watcher event - notifyWatchedEvent( - EventType.NodeDataChanged, KeeperState.SyncConnected, ledgerStr); - - // the listener should be removed from listener set and not receive an updated metadata anymore - Optional change2 = changes.take(); - assertFalse(change2.isPresent()); - assertFalse(ledgerManager.listeners.containsKey(ledgerId)); - - // verify scheduler: the listener is only triggered once - verify(scheduler, times(1)).submit(any(Runnable.class)); - verify(scheduler, times(0)).schedule( - any(Runnable.class), anyLong(), any(TimeUnit.class)); - - // no watcher is registered - assertFalse(watchers.containsKey(ledgerStr)); - } - - @Test - public void testLedgerMetadataListenerOnLedgerDeletedEvent() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - LinkedBlockingQueue> changes = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener = - (ledgerId1, metadata) -> changes.add( - Optional.ofNullable(metadata != null ? metadata.getValue() : null)); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - ledgerManager.registerLedgerMetadataListener(ledgerId, listener); - assertTrue(ledgerManager.listeners.containsKey(ledgerId)); - - // the listener will be notified with first get - LedgerMetadata change1 = changes.take().get(); - assertEquals(metadata, change1); - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // the watcher is registered for receiving watched event - assertTrue(watchers.containsKey(ledgerStr)); - - // notify the watcher event - notifyWatchedEvent( - EventType.NodeDeleted, KeeperState.SyncConnected, ledgerStr); - - // the listener should be removed from listener set and a null change is notified. - Optional change2 = changes.take(); - assertFalse(change2.isPresent()); - // no more `getData` is called. - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - // listener is automatically unregistered after a ledger is deleted. - assertFalse(ledgerManager.listeners.containsKey(ledgerId)); - } - - @Test - public void testLedgerMetadataListenerOnRetries() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - LinkedBlockingQueue changes = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener = (ledgerId1, metadata) -> changes.add(metadata.getValue()); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - - // fail the first get, so the ledger manager will retry get data again. - mockZkGetData( - ledgerStr, true, - KeeperException.Code.SESSIONEXPIRED.intValue(), null, null); - - ledgerManager.registerLedgerMetadataListener(ledgerId, listener); - assertTrue(ledgerManager.listeners.containsKey(ledgerId)); - - // the listener will not be notified with any updates - assertNull(changes.poll()); - // an retry task is scheduled - verify(scheduler, times(1)) - .schedule(any(Runnable.class), anyLong(), any(TimeUnit.class)); - // zookeeper is called once - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - // watcher is not registered since getData call is failed - assertFalse(watchers.containsKey(ledgerStr)); - - // mock get data to return a valid response - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - schedulerController.advance(Duration.ofMillis(ZK_CONNECT_BACKOFF_MS)); - - // the listener will be notified with first get - LedgerMetadata change = changes.take(); - assertEquals(metadata, change); - verify(mockZk, times(2)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // watcher is registered after successfully `getData` - assertTrue(watchers.containsKey(ledgerStr)); - } - - @Test - public void testLedgerMetadataListenerOnSessionExpired() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - LinkedBlockingQueue changes = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener = (ledgerId1, metadata) -> changes.add(metadata.getValue()); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - ledgerManager.registerLedgerMetadataListener(ledgerId, listener); - - // the listener will be notified with first get - LedgerMetadata change1 = changes.take(); - assertEquals(metadata, change1); - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // the watcher is registered for receiving watched event - assertTrue(watchers.containsKey(ledgerStr)); - Set watcherSet1 = watchers.get(ledgerStr); - assertEquals(1, watcherSet1.size()); - Watcher registeredWatcher1 = watcherSet1.stream().findFirst().get(); - - // simulate session expired - notifyWatchedEvent( - EventType.None, KeeperState.Expired, ledgerStr); - - // ledger manager will retry to read metadata again - LedgerMetadata change2 = changes.take(); - assertEquals(metadata, change2); - verify(mockZk, times(2)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // the watcher is registered for receiving watched event - assertTrue(watchers.containsKey(ledgerStr)); - Set watcherSet2 = watchers.get(ledgerStr); - assertEquals(1, watcherSet2.size()); - Watcher registeredWatcher2 = watcherSet2.stream().findFirst().get(); - - assertSame(registeredWatcher1, registeredWatcher2); - } - - @Test - public void testUnregisterLedgerMetadataListener() throws Exception { - long ledgerId = System.currentTimeMillis(); - String ledgerStr = String.valueOf(ledgerId); - - LinkedBlockingQueue changes = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener = (ledgerId1, metadata) -> changes.add(metadata.getValue()); - - Stat stat = mock(Stat.class); - when(stat.getVersion()).thenReturn(1234); - when(stat.getCtime()).thenReturn(metadata.getCtime()); - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - ledgerManager.registerLedgerMetadataListener(ledgerId, listener); - assertTrue(ledgerManager.listeners.containsKey(ledgerId)); - - // the listener will be notified with first get - LedgerMetadata change1 = changes.take(); - assertEquals(metadata, change1); - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - - // the watcher is registered for receiving watched event - assertTrue(watchers.containsKey(ledgerStr)); - Set watcherSet1 = watchers.get(ledgerStr); - assertEquals(1, watcherSet1.size()); - Watcher registeredWatcher1 = watcherSet1.stream().findFirst().get(); - - // mock get data to return an updated metadata - when(stat.getVersion()).thenReturn(1235); - mockZkGetData( - ledgerStr, true, - KeeperException.Code.OK.intValue(), serDe.serialize(metadata), stat); - - mockZkRemoveWatcher(); - - // unregister the listener - ledgerManager.unregisterLedgerMetadataListener(ledgerId, listener); - assertFalse(ledgerManager.listeners.containsKey(ledgerId)); - assertFalse(watchers.containsKey(ledgerStr)); - verify(mockZk, times(1)).removeWatches(eq(ledgerManager.getLedgerPath(ledgerId)), - any(Watcher.class), any(Watcher.WatcherType.class), any(Boolean.class), - any(VoidCallback.class), any()); - - - // notify the watcher event - notifyWatchedEvent( - EventType.NodeDataChanged, KeeperState.SyncConnected, ledgerStr); - - // since listener is already unregistered so no more `getData` is issued. - assertNull(changes.poll()); - verify(mockZk, times(1)) - .getData(anyString(), any(Watcher.class), any(DataCallback.class), any()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/CleanupLedgerManagerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/CleanupLedgerManagerTest.java deleted file mode 100644 index fabbdc7f059..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/CleanupLedgerManagerTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.meta; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link CleanupLedgerManager}. - */ -public class CleanupLedgerManagerTest { - - protected LedgerManager ledgerManager = null; - protected CleanupLedgerManager cleanupLedgerManager = null; - - @Before - public void setup() throws Exception { - ledgerManager = mock(LedgerManager.class); - CompletableFuture> future = new CompletableFuture<>(); - future.completeExceptionally(new Exception("LedgerNotExistException")); - when(ledgerManager.createLedgerMetadata(anyLong(), any())).thenReturn(future); - when(ledgerManager.readLedgerMetadata(anyLong())).thenReturn(future); - when(ledgerManager.writeLedgerMetadata(anyLong(), any(), any())).thenReturn( - future); - CompletableFuture removeFuture = new CompletableFuture<>(); - removeFuture.completeExceptionally(new Exception("LedgerNotExistException")); - when(ledgerManager.removeLedgerMetadata(anyLong(), any())).thenReturn(removeFuture); - cleanupLedgerManager = new CleanupLedgerManager(ledgerManager); - } - - @Test - public void testCreateLedgerMetadataException() throws Exception { - cleanupLedgerManager.createLedgerMetadata(anyLong(), any(LedgerMetadata.class)); - Assert.assertEquals(0, cleanupLedgerManager.getCurrentFuturePromiseSize()); - } - - @Test - public void testReadLedgerMetadataException() throws Exception { - cleanupLedgerManager.readLedgerMetadata(anyLong()); - Assert.assertEquals(0, cleanupLedgerManager.getCurrentFuturePromiseSize()); - } - - @Test - public void testWriteLedgerMetadataException() throws Exception { - cleanupLedgerManager.writeLedgerMetadata(anyLong(), any(LedgerMetadata.class), any(Version.class)); - Assert.assertEquals(0, cleanupLedgerManager.getCurrentFuturePromiseSize()); - } - - @Test - public void testRemoveLedgerMetadataException() throws Exception { - cleanupLedgerManager.removeLedgerMetadata(anyLong(), any(Version.class)); - Assert.assertEquals(0, cleanupLedgerManager.getCurrentFuturePromiseSize()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java deleted file mode 100644 index fec74a8202f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java +++ /dev/null @@ -1,788 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.meta; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.NavigableMap; -import java.util.PrimitiveIterator.OfLong; -import java.util.Queue; -import java.util.Random; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.CompactableLedgerStorage; -import org.apache.bookkeeper.bookie.EntryLocation; -import org.apache.bookkeeper.bookie.GarbageCollector; -import org.apache.bookkeeper.bookie.LastAddConfirmedUpdateNotification; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.ScanAndCompareGarbageCollector; -import org.apache.bookkeeper.bookie.StateManager; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.util.Watcher; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManager.LedgerRange; -import org.apache.bookkeeper.meta.LedgerManager.LedgerRangeIterator; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test garbage collection ledgers in ledger manager. - */ -public class GcLedgersTest extends LedgerManagerTestCase { - static final Logger LOG = LoggerFactory.getLogger(GcLedgersTest.class); - - public GcLedgersTest(Class lmFactoryCls) { - super(lmFactoryCls); - } - - private void createLedgers(int numLedgers, final Set createdLedgers) throws IOException { - BookieId selfBookie = BookieImpl.getBookieId(baseConf); - createLedgers(numLedgers, createdLedgers, selfBookie); - } - - /** - * Create ledgers. - */ - private void createLedgers(int numLedgers, final Set createdLedgers, BookieId selfBookie) - throws IOException { - final AtomicInteger expected = new AtomicInteger(numLedgers); - List ensemble = Lists.newArrayList(selfBookie); - - for (int i = 0; i < numLedgers; i++) { - getLedgerIdGenerator().generateLedgerId(new GenericCallback() { - @Override - public void operationComplete(int rc, final Long ledgerId) { - if (BKException.Code.OK != rc) { - synchronized (expected) { - int num = expected.decrementAndGet(); - if (num == 0) { - expected.notify(); - } - } - return; - } - - LedgerMetadata md = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withDigestType(DigestType.CRC32C) - .withPassword(new byte[0]) - .withEnsembleSize(1).withWriteQuorumSize(1).withAckQuorumSize(1) - .newEnsembleEntry(0L, ensemble).build(); - - getLedgerManager().createLedgerMetadata(ledgerId, md) - .whenComplete((result, exception) -> { - if (exception == null) { - activeLedgers.put(ledgerId, true); - createdLedgers.add(ledgerId); - } - synchronized (expected) { - int num = expected.decrementAndGet(); - if (num == 0) { - expected.notify(); - } - } - }); - } - }); - } - synchronized (expected) { - try { - while (expected.get() > 0) { - expected.wait(100); - } - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - } - } - } - - private void removeLedger(long ledgerId) throws Exception { - getLedgerManager().removeLedgerMetadata(ledgerId, Version.ANY).get(10, TimeUnit.SECONDS); - } - - @Test - public void testGarbageCollectLedgers() throws Exception { - int numLedgers = 100; - int numRemovedLedgers = 10; - - final Set createdLedgers = new HashSet(); - final Set removedLedgers = new HashSet(); - - // create 100 ledgers - createLedgers(numLedgers, createdLedgers); - - Random r = new Random(System.currentTimeMillis()); - final List tmpList = new ArrayList(); - tmpList.addAll(createdLedgers); - Collections.shuffle(tmpList, r); - // random remove several ledgers - for (int i = 0; i < numRemovedLedgers; i++) { - long ledgerId = tmpList.get(i); - getLedgerManager().removeLedgerMetadata(ledgerId, Version.ANY).get(); - removedLedgers.add(ledgerId); - createdLedgers.remove(ledgerId); - } - final CountDownLatch inGcProgress = new CountDownLatch(1); - final CountDownLatch createLatch = new CountDownLatch(1); - final CountDownLatch endLatch = new CountDownLatch(2); - final CompactableLedgerStorage mockLedgerStorage = new MockLedgerStorage(); - TestStatsProvider stats = new TestStatsProvider(); - final ScanAndCompareGarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(getLedgerManager(), - mockLedgerStorage, baseConf, stats.getStatsLogger("gc")); - Thread gcThread = new Thread() { - @Override - public void run() { - garbageCollector.gc(new GarbageCollector.GarbageCleaner() { - boolean paused = false; - - @Override - public void clean(long ledgerId) { - try { - mockLedgerStorage.deleteLedger(ledgerId); - } catch (IOException e) { - e.printStackTrace(); - return; - } - - if (!paused) { - inGcProgress.countDown(); - try { - createLatch.await(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - } - paused = true; - } - LOG.info("Garbage Collected ledger {}", ledgerId); - } - }); - LOG.info("Gc Thread quits."); - endLatch.countDown(); - } - }; - - Thread createThread = new Thread() { - @Override - public void run() { - try { - inGcProgress.await(); - // create 10 more ledgers - createLedgers(10, createdLedgers); - LOG.info("Finished creating 10 more ledgers."); - createLatch.countDown(); - } catch (Exception e) { - } - LOG.info("Create Thread quits."); - endLatch.countDown(); - } - }; - - createThread.start(); - gcThread.start(); - - endLatch.await(); - - // test ledgers - for (Long ledger : removedLedgers) { - assertFalse(activeLedgers.containsKey(ledger)); - } - for (Long ledger : createdLedgers) { - assertTrue(activeLedgers.containsKey(ledger)); - } - assertTrue( - "Wrong ACTIVE_LEDGER_COUNT", - garbageCollector.getNumActiveLedgers() == createdLedgers.size()); - } - - @Test - public void testGcLedgersOutsideRange() throws Exception { - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final Queue cleaned = new LinkedList(); - int numLedgers = 100; - - createLedgers(numLedgers, createdLedgers); - - MockLedgerStorage mockLedgerStorage = new MockLedgerStorage(); - TestStatsProvider stats = new TestStatsProvider(); - final ScanAndCompareGarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(getLedgerManager(), - mockLedgerStorage, baseConf, stats.getStatsLogger("gc")); - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleaned.add(ledgerId); - try { - mockLedgerStorage.deleteLedger(ledgerId); - } catch (IOException e) { - e.printStackTrace(); - fail("Exception from deleteLedger"); - } - } - }; - - garbageCollector.gc(cleaner); - assertNull("Should have cleaned nothing", cleaned.poll()); - assertTrue( - "Wrong ACTIVE_LEDGER_COUNT", - garbageCollector.getNumActiveLedgers() == numLedgers); - - long last = createdLedgers.last(); - removeLedger(last); - garbageCollector.gc(cleaner); - assertNotNull("Should have cleaned something", cleaned.peek()); - assertEquals("Should have cleaned last ledger" + last, (long) last, (long) cleaned.poll()); - - long first = createdLedgers.first(); - removeLedger(first); - garbageCollector.gc(cleaner); - assertNotNull("Should have cleaned something", cleaned.peek()); - assertEquals("Should have cleaned first ledger" + first, (long) first, (long) cleaned.poll()); - - garbageCollector.gc(cleaner); - assertTrue( - "Wrong ACTIVE_LEDGER_COUNT", - garbageCollector.getNumActiveLedgers() == (numLedgers - 2)); - - } - - @Test - public void testGcLedgersNotLast() throws Exception { - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final List cleaned = new ArrayList(); - - // Create enough ledgers to span over 4 ranges in the hierarchical ledger manager implementation - final int numLedgers = 30001; - - createLedgers(numLedgers, createdLedgers); - - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(getLedgerManager(), - new MockLedgerStorage(), baseConf, NullStatsLogger.INSTANCE); - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleaned.add(ledgerId); - } - }; - - SortedSet scannedLedgers = new TreeSet(); - LedgerRangeIterator iterator = getLedgerManager().getLedgerRanges(0); - while (iterator.hasNext()) { - LedgerRange ledgerRange = iterator.next(); - scannedLedgers.addAll(ledgerRange.getLedgers()); - } - - assertEquals(createdLedgers, scannedLedgers); - - garbageCollector.gc(cleaner); - assertTrue("Should have cleaned nothing", cleaned.isEmpty()); - - long first = createdLedgers.first(); - removeLedger(first); - garbageCollector.gc(cleaner); - assertEquals("Should have cleaned something", 1, cleaned.size()); - assertEquals("Should have cleaned first ledger" + first, (long) first, (long) cleaned.get(0)); - } - - /* - * in this scenario no ledger is created, so ledgeriterator's hasNext call would return false and next would be - * null. GarbageCollector.gc is expected to behave normally - */ - @Test - public void testGcLedgersWithNoLedgers() throws Exception { - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final List cleaned = new ArrayList(); - - // no ledger created - - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(getLedgerManager(), - new MockLedgerStorage(), baseConf, NullStatsLogger.INSTANCE); - AtomicBoolean cleanerCalled = new AtomicBoolean(false); - - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleanerCalled.set(true); - } - }; - - validateLedgerRangeIterator(createdLedgers); - - garbageCollector.gc(cleaner); - assertFalse("Should have cleaned nothing, since no ledger is created", cleanerCalled.get()); - } - - // in this scenario all the created ledgers are in one single ledger range. - @Test - public void testGcLedgersWithLedgersInSameLedgerRange() throws Exception { - baseConf.setVerifyMetadataOnGc(true); - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final SortedSet cleaned = Collections.synchronizedSortedSet(new TreeSet()); - - // Create few ledgers which span over just one ledger range in the hierarchical ledger manager implementation - final int numLedgers = 5; - - createLedgers(numLedgers, createdLedgers); - - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(getLedgerManager(), - new MockLedgerStorage(), baseConf, NullStatsLogger.INSTANCE); - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleaned.add(ledgerId); - } - }; - - validateLedgerRangeIterator(createdLedgers); - - garbageCollector.gc(cleaner); - assertTrue("Should have cleaned nothing", cleaned.isEmpty()); - - for (long ledgerId : createdLedgers) { - removeLedger(ledgerId); - } - - garbageCollector.gc(cleaner); - assertEquals("Should have cleaned all the created ledgers", createdLedgers, cleaned); - } - - /* - * in this test scenario no created ledger is deleted, but ledgeriterator is screwed up and returns hasNext to be - * false and next to be null. So even in this case it is expected not to clean any ledger's data. - * - * This testcase is needed for validating fix of bug - W-4292747. - * - * ScanAndCompareGarbageCollector/GC should clean data of ledger only if both the LedgerManager.getLedgerRanges says - * that ledger is not existing and also ledgerManager.readLedgerMetadata fails with error - * NoSuchLedgerExistsOnMetadataServerException. - * - */ - @Test - public void testGcLedgersIfLedgerManagerIteratorFails() throws Exception { - baseConf.setVerifyMetadataOnGc(true); - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final SortedSet cleaned = Collections.synchronizedSortedSet(new TreeSet()); - - // Create few ledgers - final int numLedgers = 5; - - createLedgers(numLedgers, createdLedgers); - - LedgerManager mockLedgerManager = new CleanupLedgerManager(getLedgerManager()) { - @Override - public LedgerRangeIterator getLedgerRanges(long zkOpTimeout) { - return new LedgerRangeIterator() { - @Override - public LedgerRange next() throws IOException { - return null; - } - - @Override - public boolean hasNext() throws IOException { - return false; - } - }; - } - }; - - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(mockLedgerManager, - new MockLedgerStorage(), baseConf, NullStatsLogger.INSTANCE); - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleaned.add(ledgerId); - } - }; - - validateLedgerRangeIterator(createdLedgers); - - garbageCollector.gc(cleaner); - assertTrue("Should have cleaned nothing", cleaned.isEmpty()); - } - - /* - * In this test scenario no ledger is deleted, but LedgerManager.readLedgerMetadata says there is NoSuchLedger. So - * even in that case, GarbageCollector.gc shouldn't delete ledgers data. - * - * Consider the possible scenario - when the LedgerIterator is created that ledger is not deleted, so as per - * LedgerIterator that is live ledger. But right after the LedgerIterator creation that ledger is deleted, so - * readLedgerMetadata call would return NoSuchLedger. In this testscenario we are validating that as per Iterator if - * that ledger is alive though currently that ledger is deleted, we should not clean data of that ledger. - * - * ScanAndCompareGarbageCollector/GC should clean data of ledger only if both the LedgerManager.getLedgerRanges says - * that ledger is not existing and also ledgerManager.readLedgerMetadata fails with error - * NoSuchLedgerExistsOnMetadataServerException. - * - */ - @Test - public void testGcLedgersIfReadLedgerMetadataSaysNoSuchLedger() throws Exception { - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final SortedSet cleaned = Collections.synchronizedSortedSet(new TreeSet()); - - // Create few ledgers - final int numLedgers = 5; - - createLedgers(numLedgers, createdLedgers); - - CompletableFuture> errorFuture = new CompletableFuture<>(); - errorFuture.completeExceptionally(new BKException.BKNoSuchLedgerExistsException()); - LedgerManager mockLedgerManager = new CleanupLedgerManager(getLedgerManager()) { - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - return errorFuture; - } - }; - - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(mockLedgerManager, - new MockLedgerStorage(), baseConf, NullStatsLogger.INSTANCE); - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleaned.add(ledgerId); - } - }; - - validateLedgerRangeIterator(createdLedgers); - - garbageCollector.gc(cleaner); - assertTrue("Should have cleaned nothing", cleaned.isEmpty()); - } - - /* - * In this test scenario all the created ledgers are deleted, but LedgerManager.readLedgerMetadata fails with - * ZKException. So even in this case, GarbageCollector.gc shouldn't delete ledgers data. - * - * ScanAndCompareGarbageCollector/GC should clean data of ledger only if both the LedgerManager.getLedgerRanges says - * that ledger is not existing and also ledgerManager.readLedgerMetadata fails with error - * NoSuchLedgerExistsOnMetadataServerException, but is shouldn't delete if the readLedgerMetadata fails with any - * other error. - */ - @Test - public void testGcLedgersIfReadLedgerMetadataFailsForDeletedLedgers() throws Exception { - baseConf.setVerifyMetadataOnGc(true); - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final SortedSet cleaned = Collections.synchronizedSortedSet(new TreeSet()); - - // Create few ledgers - final int numLedgers = 5; - - createLedgers(numLedgers, createdLedgers); - - CompletableFuture> errorFuture = new CompletableFuture<>(); - errorFuture.completeExceptionally(new BKException.ZKException()); - LedgerManager mockLedgerManager = new CleanupLedgerManager(getLedgerManager()) { - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - return errorFuture; - } - }; - - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(mockLedgerManager, - new MockLedgerStorage(), baseConf, NullStatsLogger.INSTANCE); - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleaned.add(ledgerId); - } - }; - - validateLedgerRangeIterator(createdLedgers); - - for (long ledgerId : createdLedgers) { - removeLedger(ledgerId); - } - - garbageCollector.gc(cleaner); - assertTrue("Should have cleaned nothing", cleaned.isEmpty()); - } - - public void validateLedgerRangeIterator(SortedSet createdLedgers) throws IOException { - SortedSet scannedLedgers = new TreeSet(); - LedgerRangeIterator iterator = getLedgerManager().getLedgerRanges(0); - while (iterator.hasNext()) { - LedgerRange ledgerRange = iterator.next(); - scannedLedgers.addAll(ledgerRange.getLedgers()); - } - - assertEquals(createdLedgers, scannedLedgers); - } - - class MockLedgerStorage implements CompactableLedgerStorage { - - @Override - public void initialize( - ServerConfiguration conf, - LedgerManager ledgerManager, - LedgerDirsManager ledgerDirsManager, - LedgerDirsManager indexDirsManager, - StatsLogger statsLogger, - ByteBufAllocator allocator) throws IOException { - } - - @Override - public void setStateManager(StateManager stateManager) {} - @Override - public void setCheckpointSource(CheckpointSource checkpointSource) {} - @Override - public void setCheckpointer(Checkpointer checkpointer) {} - - @Override - public void start() { - } - - @Override - public void shutdown() throws InterruptedException { - } - - @Override - public long getLastAddConfirmed(long ledgerId) throws IOException { - return 0; - } - - @Override - public void setExplicitLac(long ledgerId, ByteBuf lac) throws IOException { - } - - @Override - public ByteBuf getExplicitLac(long ledgerId) { - return null; - } - - @Override - public boolean ledgerExists(long ledgerId) throws IOException { - return false; - } - - @Override - public boolean entryExists(long ledgerId, long entryId) throws IOException { - return false; - } - - @Override - public boolean setFenced(long ledgerId) throws IOException { - return false; - } - - @Override - public boolean isFenced(long ledgerId) throws IOException { - return false; - } - - @Override - public void setMasterKey(long ledgerId, byte[] masterKey) throws IOException { - } - - @Override - public byte[] readMasterKey(long ledgerId) throws IOException, BookieException { - return null; - } - - @Override - public long addEntry(ByteBuf entry) throws IOException { - return 0; - } - - @Override - public ByteBuf getEntry(long ledgerId, long entryId) throws IOException { - return null; - } - - @Override - public void flush() throws IOException { - } - - @Override - public void checkpoint(Checkpoint checkpoint) throws IOException { - } - - @Override - public void deleteLedger(long ledgerId) throws IOException { - activeLedgers.remove(ledgerId); - } - - @Override - public Iterable getActiveLedgersInRange(long firstLedgerId, long lastLedgerId) { - NavigableMap bkActiveLedgersSnapshot = activeLedgers.snapshot(); - Map subBkActiveLedgers = bkActiveLedgersSnapshot - .subMap(firstLedgerId, true, lastLedgerId, false); - - return subBkActiveLedgers.keySet(); - } - - @Override - public void updateEntriesLocations(Iterable locations) throws IOException { - } - - @Override - public void registerLedgerDeletionListener(LedgerDeletionListener listener) { - } - - @Override - public void flushEntriesLocationsIndex() throws IOException { - } - - @Override - public boolean waitForLastAddConfirmedUpdate(long ledgerId, - long previousLAC, - Watcher watcher) - throws IOException { - return false; - } - - @Override - public void cancelWaitForLastAddConfirmedUpdate(long ledgerId, - Watcher watcher) - throws IOException { - } - - @Override - public OfLong getListOfEntriesOfLedger(long ledgerId) throws IOException { - return null; - } - - @Override - public void setLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public boolean hasLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public void clearLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public EnumSet getStorageStateFlags() throws IOException { - return EnumSet.noneOf(StorageState.class); - } - - @Override - public void setStorageStateFlag(StorageState flag) throws IOException { - } - - @Override - public void clearStorageStateFlag(StorageState flag) throws IOException { - } - } - - /** - * Verifies that gc should cleaned up overreplicatd ledgers which is not - * owned by the bookie anymore. - * - * @throws Exception - */ - @Test - public void testGcLedgersForOverreplicated() throws Exception { - baseConf.setVerifyMetadataOnGc(true); - final SortedSet createdLedgers = Collections.synchronizedSortedSet(new TreeSet()); - final SortedSet cleaned = Collections.synchronizedSortedSet(new TreeSet()); - - // Create few ledgers - final int numLedgers = 5; - - BookieId bookieAddress = new BookieSocketAddress("192.0.0.1", 1234).toBookieId(); - createLedgers(numLedgers, createdLedgers, bookieAddress); - - LedgerManager mockLedgerManager = new CleanupLedgerManager(getLedgerManager()) { - @Override - public LedgerRangeIterator getLedgerRanges(long zkOpTimeout) { - return new LedgerRangeIterator() { - @Override - public LedgerRange next() throws IOException { - return null; - } - - @Override - public boolean hasNext() throws IOException { - return false; - } - }; - } - }; - - final GarbageCollector garbageCollector = new ScanAndCompareGarbageCollector(mockLedgerManager, - new MockLedgerStorage(), baseConf, NullStatsLogger.INSTANCE); - GarbageCollector.GarbageCleaner cleaner = new GarbageCollector.GarbageCleaner() { - @Override - public void clean(long ledgerId) { - LOG.info("Cleaned {}", ledgerId); - cleaned.add(ledgerId); - } - }; - - validateLedgerRangeIterator(createdLedgers); - - garbageCollector.gc(cleaner); - assertEquals("Should have cleaned all ledgers", cleaned.size(), numLedgers); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerIteratorTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerIteratorTest.java deleted file mode 100644 index 80cc33bcabd..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerIteratorTest.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.meta; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.meta.LedgerManager.LedgerRangeIterator; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.util.MathUtils; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.bookkeeper.versioning.Version; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Test; - -/** - * Test the ledger manager iterator. - */ -public class LedgerManagerIteratorTest extends LedgerManagerTestCase { - public LedgerManagerIteratorTest(Class lmFactoryCls) { - super(lmFactoryCls); - } - - /** - * Remove ledger using lm syncronously. - * - * @param lm - * @param ledgerId - * @throws InterruptedException - */ - void removeLedger(LedgerManager lm, Long ledgerId) throws Exception { - lm.removeLedgerMetadata(ledgerId, Version.ANY).get(); - } - - /** - * Create ledger using lm syncronously. - * - * @param lm - * @param ledgerId - * @throws InterruptedException - */ - void createLedger(LedgerManager lm, Long ledgerId) throws Exception { - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId()); - LedgerMetadata meta = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .withPassword("passwd".getBytes()) - .withDigestType(BookKeeper.DigestType.CRC32.toApiDigestType()) - .newEnsembleEntry(0L, ensemble) - .build(); - lm.createLedgerMetadata(ledgerId, meta).get(); - } - - static Set ledgerRangeToSet(LedgerRangeIterator lri) throws IOException { - Set ret = new TreeSet<>(); - long last = -1; - while (lri.hasNext()) { - LedgerManager.LedgerRange lr = lri.next(); - assertFalse("ledger range must not be empty", lr.getLedgers().isEmpty()); - assertTrue("ledger ranges must not overlap", last < lr.start()); - ret.addAll(lr.getLedgers()); - last = lr.end(); - } - return ret; - } - - static Set getLedgerIdsByUsingAsyncProcessLedgers(LedgerManager lm) throws InterruptedException{ - Set ledgersReadAsync = ConcurrentHashMap.newKeySet(); - CountDownLatch latch = new CountDownLatch(1); - AtomicInteger finalRC = new AtomicInteger(); - - lm.asyncProcessLedgers((ledgerId, callback) -> { - ledgersReadAsync.add(ledgerId); - callback.processResult(BKException.Code.OK, null, null); - }, (rc, s, obj) -> { - finalRC.set(rc); - latch.countDown(); - }, null, BKException.Code.OK, BKException.Code.ReadException); - - latch.await(); - assertEquals("Final RC of asyncProcessLedgers", BKException.Code.OK, finalRC.get()); - return ledgersReadAsync; - } - - @Test - public void testIterateNoLedgers() throws Exception { - LedgerManager lm = getLedgerManager(); - LedgerRangeIterator lri = lm.getLedgerRanges(0); - assertNotNull(lri); - if (lri.hasNext()) { - lri.next(); - } - - assertEquals(false, lri.hasNext()); - } - - @Test - public void testSingleLedger() throws Throwable { - LedgerManager lm = getLedgerManager(); - - long id = 2020202; - createLedger(lm, id); - - LedgerRangeIterator lri = lm.getLedgerRanges(0); - assertNotNull(lri); - Set lids = ledgerRangeToSet(lri); - assertEquals(lids.size(), 1); - assertEquals(lids.iterator().next().longValue(), id); - - Set ledgersReadAsync = getLedgerIdsByUsingAsyncProcessLedgers(lm); - assertEquals("Comparing LedgersIds read asynchronously", lids, ledgersReadAsync); - } - - @Test - public void testTwoLedgers() throws Throwable { - LedgerManager lm = getLedgerManager(); - - Set ids = new TreeSet<>(Arrays.asList(101010101L, 2020340302L)); - for (Long id: ids) { - createLedger(lm, id); - } - - LedgerRangeIterator lri = lm.getLedgerRanges(0); - assertNotNull(lri); - Set returnedIds = ledgerRangeToSet(lri); - assertEquals(ids, returnedIds); - - Set ledgersReadAsync = getLedgerIdsByUsingAsyncProcessLedgers(lm); - assertEquals("Comparing LedgersIds read asynchronously", ids, ledgersReadAsync); - } - - @Test - public void testSeveralContiguousLedgers() throws Throwable { - LedgerManager lm = getLedgerManager(); - - Set ids = new TreeSet<>(); - for (long i = 0; i < 2000; ++i) { - createLedger(lm, i); - ids.add(i); - } - - LedgerRangeIterator lri = lm.getLedgerRanges(0); - assertNotNull(lri); - Set returnedIds = ledgerRangeToSet(lri); - assertEquals(ids, returnedIds); - - Set ledgersReadAsync = getLedgerIdsByUsingAsyncProcessLedgers(lm); - assertEquals("Comparing LedgersIds read asynchronously", ids, ledgersReadAsync); - } - - @Test - public void testRemovalOfNodeJustTraversed() throws Throwable { - if (baseConf.getLedgerManagerFactoryClass() - != LongHierarchicalLedgerManagerFactory.class) { - return; - } - LedgerManager lm = getLedgerManager(); - - /* For LHLM, first two should be leaves on the same node, second should be on adjacent level 4 node - * Removing all 3 once the iterator hits the first should result in the whole tree path ending - * at that node disappearing. If this happens after the iterator stops at that leaf, it should - * result in a few NodeExists errors (handled silently) as the iterator fails back up the tree - * to the next path. - */ - Set toRemove = new TreeSet<>( - Arrays.asList( - 3394498498348983841L, - 3394498498348983842L, - 3394498498348993841L)); - - long first = 2345678901234567890L; - // Nodes which should be listed anyway - Set mustHave = new TreeSet<>( - Arrays.asList( - first, - 6334994393848474732L)); - - Set ids = new TreeSet<>(); - ids.addAll(toRemove); - ids.addAll(mustHave); - for (Long id: ids) { - createLedger(lm, id); - } - - Set found = new TreeSet<>(); - LedgerRangeIterator lri = lm.getLedgerRanges(0); - while (lri.hasNext()) { - LedgerManager.LedgerRange lr = lri.next(); - found.addAll(lr.getLedgers()); - - if (lr.getLedgers().contains(first)) { - for (long id: toRemove) { - removeLedger(lm, id); - } - toRemove.clear(); - } - } - - for (long id: mustHave) { - assertTrue(found.contains(id)); - } - } - - @Test - public void validateEmptyL4PathSkipped() throws Throwable { - if (baseConf.getLedgerManagerFactoryClass() - != LongHierarchicalLedgerManagerFactory.class) { - return; - } - LedgerManager lm = getLedgerManager(); - - Set ids = new TreeSet<>( - Arrays.asList( - 2345678901234567890L, - 3394498498348983841L, - 6334994393848474732L, - 7349370101927398483L)); - for (Long id: ids) { - createLedger(lm, id); - } - - String[] paths = { - "/ledgers/633/4994/3938/4948", // Empty L4 path, must be skipped - - }; - - for (String path : paths) { - ZkUtils.createFullPathOptimistic( - zkc, - path, "data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } - - LedgerRangeIterator lri = lm.getLedgerRanges(0); - assertNotNull(lri); - Set returnedIds = ledgerRangeToSet(lri); - assertEquals(ids, returnedIds); - - Set ledgersReadAsync = getLedgerIdsByUsingAsyncProcessLedgers(lm); - assertEquals("Comparing LedgersIds read asynchronously", ids, ledgersReadAsync); - - lri = lm.getLedgerRanges(0); - int emptyRanges = 0; - while (lri.hasNext()) { - if (lri.next().getLedgers().isEmpty()) { - emptyRanges++; - } - } - assertEquals(0, emptyRanges); - } - - @Test - public void testWithSeveralIncompletePaths() throws Throwable { - if (baseConf.getLedgerManagerFactoryClass() - != LongHierarchicalLedgerManagerFactory.class) { - return; - } - LedgerManager lm = getLedgerManager(); - - Set ids = new TreeSet<>( - Arrays.asList( - 2345678901234567890L, - 3394498498348983841L, - 6334994393848474732L, - 7349370101927398483L)); - for (Long id: ids) { - createLedger(lm, id); - } - - String[] paths = { - "/ledgers/000/0000/0000", // top level, W-4292762 - "/ledgers/234/5678/9999", // shares two path segments with the first one, comes after - "/ledgers/339/0000/0000", // shares one path segment with the second one, comes first - "/ledgers/633/4994/3938/0000", // shares three path segments with the third one, comes first - "/ledgers/922/3372/0000/0000", // close to max long, at end - - }; - for (String path : paths) { - ZkUtils.createFullPathOptimistic( - zkc, - path, "data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } - - LedgerRangeIterator lri = lm.getLedgerRanges(0); - assertNotNull(lri); - Set returnedIds = ledgerRangeToSet(lri); - assertEquals(ids, returnedIds); - - Set ledgersReadAsync = getLedgerIdsByUsingAsyncProcessLedgers(lm); - assertEquals("Comparing LedgersIds read asynchronously", ids, ledgersReadAsync); - } - - @Test - public void checkConcurrentModifications() throws Throwable { - final int numWriters = 10; - final int numCheckers = 10; - final int numLedgers = 100; - final long runtime = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS); - final boolean longRange = - baseConf.getLedgerManagerFactoryClass() == LongHierarchicalLedgerManagerFactory.class; - - final Set mustExist = new TreeSet<>(); - LedgerManager lm = getLedgerManager(); - Random rng = new Random(); - for (int i = 0; i < numLedgers; ++i) { - long lid = Math.abs(rng.nextLong()); - if (!longRange) { - lid %= 1000000; - } - createLedger(lm, lid); - mustExist.add(lid); - } - - final long start = MathUtils.nowInNano(); - final CountDownLatch latch = new CountDownLatch(1); - ArrayList> futures = new ArrayList<>(); - ExecutorService executor = Executors.newCachedThreadPool(); - final ConcurrentSkipListSet createdLedgers = new ConcurrentSkipListSet<>(); - for (int i = 0; i < numWriters; ++i) { - Future f = executor.submit(() -> { - LedgerManager writerLM = getIndependentLedgerManager(); - Random writerRNG = new Random(rng.nextLong()); - - latch.await(); - - while (MathUtils.elapsedNanos(start) < runtime) { - long candidate = 0; - do { - candidate = Math.abs(writerRNG.nextLong()); - if (!longRange) { - candidate %= 1000000; - } - } while (mustExist.contains(candidate) || !createdLedgers.add(candidate)); - - createLedger(writerLM, candidate); - removeLedger(writerLM, candidate); - } - return null; - }); - futures.add(f); - } - - for (int i = 0; i < numCheckers; ++i) { - Future f = executor.submit(() -> { - LedgerManager checkerLM = getIndependentLedgerManager(); - latch.await(); - - while (MathUtils.elapsedNanos(start) < runtime) { - LedgerRangeIterator lri = checkerLM.getLedgerRanges(0); - Set returnedIds = ledgerRangeToSet(lri); - for (long id: mustExist) { - assertTrue(returnedIds.contains(id)); - } - - Set ledgersReadAsync = getLedgerIdsByUsingAsyncProcessLedgers(checkerLM); - for (long id: mustExist) { - assertTrue(ledgersReadAsync.contains(id)); - } - } - return null; - }); - futures.add(f); - } - - latch.countDown(); - for (Future f : futures) { - f.get(); - } - executor.shutdownNow(); - } - - @SuppressWarnings("deprecation") - @Test - public void testLedgerParentNode() throws Throwable { - /* - * this testcase applies only ZK based ledgermanager so it doesnt work - * for MSLedgerManager - */ - Assume.assumeTrue(!baseConf.getLedgerManagerFactoryClass().equals(MSLedgerManagerFactory.class)); - AbstractZkLedgerManager lm = (AbstractZkLedgerManager) getLedgerManager(); - List ledgerIds; - if (baseConf.getLedgerManagerFactoryClass().equals(HierarchicalLedgerManagerFactory.class) - || baseConf.getLedgerManagerFactoryClass().equals(LongHierarchicalLedgerManagerFactory.class)) { - ledgerIds = Arrays.asList(100L, (Integer.MAX_VALUE * 10L)); - } else { - ledgerIds = Arrays.asList(100L, (Integer.MAX_VALUE - 10L)); - } - for (long ledgerId : ledgerIds) { - String fullLedgerPath = lm.getLedgerPath(ledgerId); - String ledgerPath = fullLedgerPath.replaceAll( - ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf) + "/", - ""); - String[] znodesOfLedger = ledgerPath.split("/"); - Assert.assertTrue(znodesOfLedger[0] + " is supposed to be valid parent ", - lm.isLedgerParentNode(znodesOfLedger[0])); - } - } - - @SuppressWarnings("deprecation") - @Test - public void testLedgerManagerFormat() throws Throwable { - String zkLedgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf); - /* - * this testcase applies only ZK based ledgermanager so it doesnt work - * for MSLedgerManager - */ - Assume.assumeTrue(!baseConf.getLedgerManagerFactoryClass().equals(MSLedgerManagerFactory.class)); - AbstractZkLedgerManager lm = (AbstractZkLedgerManager) getLedgerManager(); - Collection ids = Arrays.asList(1234567890L, 2L, 32345L, 23456789L); - if (baseConf.getLedgerManagerFactoryClass().equals(HierarchicalLedgerManagerFactory.class) - || baseConf.getLedgerManagerFactoryClass().equals(LongHierarchicalLedgerManagerFactory.class)) { - ids = new ArrayList(ids); - ids.add(Integer.MAX_VALUE * 2L); - ids.add(1234567891234L); - } - for (Long id : ids) { - createLedger(lm, id); - } - - // create some invalid nodes under zkLedgersRootPath - Collection invalidZnodes = Arrays.asList("12345", "12345678901L", "abc", "123d"); - for (String invalidZnode : invalidZnodes) { - ZkUtils.createFullPathOptimistic(zkc, zkLedgersRootPath + "/" + invalidZnode, - "data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } - - /* - * get the count of total children under zkLedgersRootPath and also - * count of the parent nodes of ledgers under zkLedgersRootPath - */ - List childrenOfLedgersRootPath = zkc.getChildren(zkLedgersRootPath, false); - int totalChildrenOfLedgersRootPath = childrenOfLedgersRootPath.size(); - int totalParentNodesOfLedgers = 0; - for (String childOfLedgersRootPath : childrenOfLedgersRootPath) { - if (lm.isLedgerParentNode(childOfLedgersRootPath)) { - totalParentNodesOfLedgers++; - } - } - - /* - * after ledgermanagerfactory format only the znodes of created ledgers - * under zkLedgersRootPath should be deleted recursively but not - * specialnode or invalid nodes created above - */ - ledgerManagerFactory.format(baseConf, - new ZkLayoutManager(zkc, zkLedgersRootPath, ZkUtils.getACLs(baseConf))); - List childrenOfLedgersRootPathAfterFormat = zkc.getChildren(zkLedgersRootPath, false); - int totalChildrenOfLedgersRootPathAfterFormat = childrenOfLedgersRootPathAfterFormat.size(); - Assert.assertEquals("totalChildrenOfLedgersRootPathAfterFormat", - totalChildrenOfLedgersRootPath - totalParentNodesOfLedgers, totalChildrenOfLedgersRootPathAfterFormat); - - Assert.assertTrue("ChildrenOfLedgersRootPathAfterFormat should contain all the invalid znodes created", - childrenOfLedgersRootPathAfterFormat.containsAll(invalidZnodes)); - } - - @Test - public void hierarchicalLedgerManagerAsyncProcessLedgersTest() throws Throwable { - Assume.assumeTrue(baseConf.getLedgerManagerFactoryClass().equals(HierarchicalLedgerManagerFactory.class)); - LedgerManager lm = getLedgerManager(); - LedgerRangeIterator lri = lm.getLedgerRanges(0); - - Set ledgerIds = new TreeSet<>(Arrays.asList(1234L, 123456789123456789L)); - for (Long ledgerId : ledgerIds) { - createLedger(lm, ledgerId); - } - Set ledgersReadThroughIterator = ledgerRangeToSet(lri); - assertEquals("Comparing LedgersIds read through Iterator", ledgerIds, ledgersReadThroughIterator); - Set ledgersReadAsync = getLedgerIdsByUsingAsyncProcessLedgers(lm); - assertEquals("Comparing LedgersIds read asynchronously", ledgerIds, ledgersReadAsync); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerTestCase.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerTestCase.java deleted file mode 100644 index 13272ab51c4..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerTestCase.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.meta; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; -import java.util.NavigableMap; -import java.util.Optional; -import java.util.PrimitiveIterator.OfLong; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.CheckpointSource; -import org.apache.bookkeeper.bookie.CheckpointSource.Checkpoint; -import org.apache.bookkeeper.bookie.Checkpointer; -import org.apache.bookkeeper.bookie.CompactableLedgerStorage; -import org.apache.bookkeeper.bookie.EntryLocation; -import org.apache.bookkeeper.bookie.LastAddConfirmedUpdateNotification; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.StateManager; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.common.util.Watcher; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.SnapshotMap; -import org.junit.After; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * Test case to run over serveral ledger managers. - */ -@RunWith(Parameterized.class) -public abstract class LedgerManagerTestCase extends BookKeeperClusterTestCase { - - protected MetadataClientDriver clientDriver; - protected Class lmFactoryClass; - protected LedgerManagerFactory ledgerManagerFactory; - protected LedgerManager ledgerManager = null; - protected LedgerIdGenerator ledgerIdGenerator = null; - protected SnapshotMap activeLedgers = null; - protected OrderedScheduler scheduler; - - public LedgerManagerTestCase(Class lmFactoryCls) { - this(lmFactoryCls, 0); - } - - public LedgerManagerTestCase(Class lmFactoryCls, int numBookies) { - super(numBookies); - activeLedgers = new SnapshotMap(); - this.lmFactoryClass = lmFactoryCls; - baseConf.setLedgerManagerFactoryClass(lmFactoryCls); - baseClientConf.setLedgerManagerFactoryClass(lmFactoryCls); - } - - @SuppressWarnings("deprecation") - @Override - protected String getMetadataServiceUri(String ledgersRootPath) { - String ledgerManagerType; - if (lmFactoryClass == org.apache.bookkeeper.meta.FlatLedgerManagerFactory.class) { - ledgerManagerType = org.apache.bookkeeper.meta.FlatLedgerManagerFactory.NAME; - } else if (lmFactoryClass == LongHierarchicalLedgerManagerFactory.class) { - ledgerManagerType = LongHierarchicalLedgerManagerFactory.NAME; - } else if (lmFactoryClass == org.apache.bookkeeper.meta.MSLedgerManagerFactory.class) { - ledgerManagerType = org.apache.bookkeeper.meta.MSLedgerManagerFactory.NAME; - } else { - ledgerManagerType = HierarchicalLedgerManagerFactory.NAME; - } - return zkUtil.getMetadataServiceUri(ledgersRootPath, ledgerManagerType); - } - - public LedgerManager getIndependentLedgerManager() { - return ledgerManagerFactory.newLedgerManager(); - } - - public LedgerManager getLedgerManager() { - if (null == ledgerManager) { - ledgerManager = ledgerManagerFactory.newLedgerManager(); - } - return ledgerManager; - } - - public LedgerIdGenerator getLedgerIdGenerator() throws IOException { - if (null == ledgerIdGenerator) { - ledgerIdGenerator = ledgerManagerFactory.newLedgerIdGenerator(); - } - return ledgerIdGenerator; - } - - @SuppressWarnings("deprecation") - @Parameters - public static Collection configs() { - return Arrays.asList(new Object[][] { - { FlatLedgerManagerFactory.class }, - { HierarchicalLedgerManagerFactory.class }, - { LongHierarchicalLedgerManagerFactory.class }, - { MSLedgerManagerFactory.class }, - }); - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduler") - .numThreads(1) - .build(); - - clientDriver = MetadataDrivers.getClientDriver( - URI.create(baseClientConf.getMetadataServiceUri())); - clientDriver.initialize( - baseClientConf, - scheduler, - NullStatsLogger.INSTANCE, - Optional.empty()); - ledgerManagerFactory = clientDriver.getLedgerManagerFactory(); - } - - @After - @Override - public void tearDown() throws Exception { - if (null != ledgerManager) { - ledgerManager.close(); - } - if (null != clientDriver) { - clientDriver.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - super.tearDown(); - } - - /** - * Mocked ledger storage. - */ - public class MockLedgerStorage implements CompactableLedgerStorage { - - @Override - public void initialize( - ServerConfiguration conf, - LedgerManager ledgerManager, - LedgerDirsManager ledgerDirsManager, - LedgerDirsManager indexDirsManager, - StatsLogger statsLogger, - ByteBufAllocator allocator) throws IOException { - } - - @Override - public void setStateManager(StateManager stateManager) {} - @Override - public void setCheckpointSource(CheckpointSource checkpointSource) {} - @Override - public void setCheckpointer(Checkpointer checkpointer) {} - - @Override - public void start() { - } - - @Override - public void shutdown() throws InterruptedException { - } - - @Override - public boolean ledgerExists(long ledgerId) throws IOException { - return false; - } - - @Override - public boolean entryExists(long ledgerId, long entryId) throws IOException { - return false; - } - - @Override - public boolean setFenced(long ledgerId) throws IOException { - return false; - } - - @Override - public boolean isFenced(long ledgerId) throws IOException { - return false; - } - - @Override - public void setMasterKey(long ledgerId, byte[] masterKey) throws IOException { - } - - @Override - public byte[] readMasterKey(long ledgerId) throws IOException, BookieException { - return null; - } - - @Override - public long addEntry(ByteBuf entry) throws IOException { - return 0; - } - - @Override - public ByteBuf getEntry(long ledgerId, long entryId) throws IOException { - return null; - } - - @Override - public long getLastAddConfirmed(long ledgerId) throws IOException { - return 0; - } - - @Override - public void flush() throws IOException { - } - - @Override - public void checkpoint(Checkpoint checkpoint) throws IOException { - } - - @Override - public void registerLedgerDeletionListener(LedgerDeletionListener listener) { - } - - @Override - public void deleteLedger(long ledgerId) throws IOException { - activeLedgers.remove(ledgerId); - } - - @Override - public Iterable getActiveLedgersInRange(long firstLedgerId, long lastLedgerId) { - NavigableMap bkActiveLedgersSnapshot = activeLedgers.snapshot(); - Map subBkActiveLedgers = bkActiveLedgersSnapshot - .subMap(firstLedgerId, true, lastLedgerId, false); - - return subBkActiveLedgers.keySet(); - } - - @Override - public void updateEntriesLocations(Iterable locations) throws IOException { - } - - @Override - public void flushEntriesLocationsIndex() throws IOException { - } - - @Override - public boolean waitForLastAddConfirmedUpdate(long ledgerId, - long previousLAC, - Watcher watcher) - throws IOException { - return false; - } - - @Override - public void cancelWaitForLastAddConfirmedUpdate(long ledgerId, - Watcher watcher) - throws IOException { - } - - @Override - public void setExplicitLac(long ledgerId, ByteBuf lac) throws IOException { - } - - @Override - public ByteBuf getExplicitLac(long ledgerId) { - return null; - } - - @Override - public OfLong getListOfEntriesOfLedger(long ledgerId) { - return null; - } - - @Override - public void setLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public boolean hasLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public void clearLimboState(long ledgerId) throws IOException { - throw new UnsupportedOperationException( - "Limbo state only supported for DbLedgerStorage"); - } - - @Override - public EnumSet getStorageStateFlags() throws IOException { - return EnumSet.noneOf(StorageState.class); - } - - @Override - public void setStorageStateFlag(StorageState flag) throws IOException { - } - - @Override - public void clearStorageStateFlag(StorageState flag) throws IOException { - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerMetadataCreationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerMetadataCreationTest.java deleted file mode 100644 index 2bba38a9459..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerMetadataCreationTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.meta; - -import static org.junit.Assert.assertTrue; - -import java.util.Random; -import java.util.Set; -import java.util.Vector; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.zookeeper.ZooKeeper; -import org.junit.Assume; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the creation of ledger metadata. - */ -public class LedgerMetadataCreationTest extends LedgerManagerTestCase { - static final Logger LOG = LoggerFactory.getLogger(LedgerMetadataCreationTest.class); - - public LedgerMetadataCreationTest(Class lmFactoryCls) { - super(lmFactoryCls, 4); - baseConf.setGcWaitTime(100000); - } - - @Test - public void testLedgerCreationAndDeletionWithRandomLedgerIds() throws Exception { - testExecution(true); - } - - @Test - public void testLedgerCreationAndDeletion() throws Exception{ - testExecution(false); - } - - public void testExecution(boolean randomLedgerId) throws Exception { - Set createRequestsLedgerIds = ConcurrentHashMap.newKeySet(); - ConcurrentLinkedDeque existingLedgerIds = new ConcurrentLinkedDeque(); - - Vector failedCreates = new Vector(); - Vector failedDeletes = new Vector(); - BookKeeper bookKeeper = new BookKeeper(baseClientConf); - - ExecutorService executor = Executors.newFixedThreadPool(300); - Random rand = new Random(); - int numberOfOperations = 20000; - for (int i = 0; i < numberOfOperations; i++) { - int iteration = i; - if (rand.nextBoolean() || existingLedgerIds.isEmpty()) { - executor.submit(() -> { - long ledgerId = -1; - try { - if (randomLedgerId) { - do { - ledgerId = Math.abs(rand.nextLong()); - if (!baseClientConf.getLedgerManagerFactoryClass() - .equals(LongHierarchicalLedgerManagerFactory.class)) { - /* - * since LongHierarchicalLedgerManager - * supports ledgerIds of decimal length upto - * 19 digits but other LedgerManagers only - * upto 10 decimals - */ - ledgerId %= 9999999999L; - } - } while (!createRequestsLedgerIds.add(ledgerId)); - } else { - ledgerId = iteration; - } - bookKeeper.createLedgerAdv(ledgerId, 3, 2, 2, DigestType.CRC32, "passwd".getBytes(), null); - existingLedgerIds.add(ledgerId); - } catch (Exception e) { - LOG.error("Got Exception while creating Ledger with ledgerId " + ledgerId, e); - failedCreates.add(ledgerId); - } - }); - } else { - executor.submit(() -> { - Long ledgerId = null; - if (rand.nextBoolean()) { - ledgerId = existingLedgerIds.pollFirst(); - } else { - ledgerId = existingLedgerIds.pollLast(); - } - if (ledgerId == null) { - return; - } - try { - bookKeeper.deleteLedger(ledgerId); - } catch (Exception e) { - LOG.error("Got Exception while deleting Ledger with ledgerId " + ledgerId, e); - failedDeletes.add(ledgerId); - } - }); - } - } - executor.shutdown(); - assertTrue("All the ledger create/delete operations should have'been completed", - executor.awaitTermination(120, TimeUnit.SECONDS)); - assertTrue("There should be no failed creates. But there are " + failedCreates.size() + " failedCreates", - failedCreates.isEmpty()); - assertTrue("There should be no failed deletes. But there are " + failedDeletes.size() + " failedDeletes", - failedDeletes.isEmpty()); - bookKeeper.close(); - } - - @Test - public void testParentNodeDeletion() throws Exception { - /* - * run this testcase only for HierarchicalLedgerManager and - * LongHierarchicalLedgerManager, since we do recursive zNode deletes - * only for HierarchicalLedgerManager - */ - Assume.assumeTrue((baseClientConf.getLedgerManagerFactoryClass().equals(HierarchicalLedgerManagerFactory.class) - || baseClientConf.getLedgerManagerFactoryClass().equals(LongHierarchicalLedgerManagerFactory.class))); - - ZooKeeper zkc = new ZooKeeper(zkUtil.getZooKeeperConnectString(), 10000, null); - BookKeeper bookKeeper = new BookKeeper(baseClientConf); - bookKeeper.createLedgerAdv(1, 3, 2, 2, DigestType.CRC32, "passwd".getBytes(), null); - String ledgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseClientConf); - String parentZnodePath; - if (baseClientConf.getLedgerManagerFactoryClass().equals(HierarchicalLedgerManagerFactory.class)) { - /* - * in HierarchicalLedgerManager (ledgersRootPath)/00/0000/L0001 - * would be the path of the znode for ledger - 1. So when ledger - 1 - * is deleted, (ledgersRootPath)/00 should also be deleted since - * there are no other children znodes - */ - parentZnodePath = ledgersRootPath + "/00"; - - } else { - /* - * in LongHierarchicalLedgerManager - * (ledgersRootPath)/000/0000/0000/0000/L0001 would be the path of - * the znode for ledger - 1. So when ledger - 1 is deleted, - * (ledgersRootPath)/000 should also be deleted since there are no - * other children znodes - */ - parentZnodePath = ledgersRootPath + "/000"; - } - assertTrue(parentZnodePath + " zNode should exist", null != zkc.exists(parentZnodePath, false)); - bookKeeper.deleteLedger(1); - assertTrue(parentZnodePath + " zNode should not exist anymore", null == zkc.exists(parentZnodePath, false)); - bookKeeper.close(); - zkc.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MetadataDriversTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MetadataDriversTest.java deleted file mode 100644 index 90f956a8c86..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MetadataDriversTest.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta; - -import static org.apache.bookkeeper.meta.MetadataDrivers.BK_METADATA_BOOKIE_DRIVERS_PROPERTY; -import static org.apache.bookkeeper.meta.MetadataDrivers.BK_METADATA_CLIENT_DRIVERS_PROPERTY; -import static org.apache.bookkeeper.meta.MetadataDrivers.ZK_BOOKIE_DRIVER_CLASS; -import static org.apache.bookkeeper.meta.MetadataDrivers.ZK_CLIENT_DRIVER_CLASS; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Maps; -import java.net.URI; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationClient; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataDrivers.MetadataBookieDriverInfo; -import org.apache.bookkeeper.meta.MetadataDrivers.MetadataClientDriverInfo; -import org.apache.bookkeeper.meta.exceptions.MetadataException; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.commons.lang3.StringUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link MetadataDrivers}. - */ -public class MetadataDriversTest { - - abstract static class TestClientDriver implements MetadataClientDriver { - - @Override - public MetadataClientDriver initialize(ClientConfiguration conf, - ScheduledExecutorService scheduler, - StatsLogger statsLogger, - Optional ctx) throws MetadataException { - return this; - } - - @Override - public RegistrationClient getRegistrationClient() { - return mock(RegistrationClient.class); - } - - @Override - public LedgerManagerFactory getLedgerManagerFactory() throws MetadataException { - return mock(LedgerManagerFactory.class); - } - - @Override - public LayoutManager getLayoutManager() { - return mock(LayoutManager.class); - } - - @Override - public void close() { - } - - @Override - public void setSessionStateListener(SessionStateListener sessionStateListener) { - } - } - - static class ClientDriver1 extends TestClientDriver { - - @Override - public String getScheme() { - return "driver1"; - } - - - } - - static class ClientDriver2 extends TestClientDriver { - - @Override - public String getScheme() { - return "driver2"; - } - - } - - abstract static class TestBookieDriver implements MetadataBookieDriver { - @Override - public MetadataBookieDriver initialize(ServerConfiguration conf, - StatsLogger statsLogger) throws MetadataException { - return this; - } - - @Override - public RegistrationManager createRegistrationManager() { - return mock(RegistrationManager.class); - } - - @Override - public LedgerManagerFactory getLedgerManagerFactory() throws MetadataException { - return mock(LedgerManagerFactory.class); - } - - @Override - public LayoutManager getLayoutManager() { - return mock(LayoutManager.class); - } - - @Override - public void close() { - - } - } - - static class BookieDriver1 extends TestBookieDriver { - - @Override - public String getScheme() { - return "driver1"; - } - - } - - static class BookieDriver2 extends TestBookieDriver { - - @Override - public String getScheme() { - return "driver2"; - } - - } - - private Map savedClientDrivers; - private Map savedBookieDrivers; - - @Before - public void setup() { - savedClientDrivers = Maps.newHashMap(MetadataDrivers.getClientDrivers()); - savedBookieDrivers = Maps.newHashMap(MetadataDrivers.getBookieDrivers()); - } - - @After - public void teardown() { - MetadataDrivers.getClientDrivers().clear(); - MetadataDrivers.getClientDrivers().putAll(savedClientDrivers); - MetadataDrivers.getBookieDrivers().clear(); - MetadataDrivers.getBookieDrivers().putAll(savedBookieDrivers); - } - - @Test - public void testDefaultDrivers() { - MetadataClientDriver clientDriver = MetadataDrivers.getClientDriver("zk"); - assertEquals( - ZK_CLIENT_DRIVER_CLASS, - clientDriver.getClass().getName()); - clientDriver = MetadataDrivers.getClientDriver(URI.create("zk+hierarchical://127.0.0.1/ledgers")); - assertEquals( - ZK_CLIENT_DRIVER_CLASS, - clientDriver.getClass().getName()); - - MetadataBookieDriver bookieDriver = MetadataDrivers.getBookieDriver("zk"); - assertEquals( - ZK_BOOKIE_DRIVER_CLASS, - bookieDriver.getClass().getName()); - bookieDriver = MetadataDrivers.getBookieDriver(URI.create("zk+hierarchical://127.0.0.1/ledgers")); - assertEquals( - ZK_BOOKIE_DRIVER_CLASS, - bookieDriver.getClass().getName()); - } - - @Test(expected = NullPointerException.class) - public void testClientDriverNullScheme() { - MetadataDrivers.getClientDriver((String) null); - } - - @Test(expected = NullPointerException.class) - public void testBookieDriverNullScheme() { - MetadataDrivers.getBookieDriver((String) null); - } - - @Test(expected = NullPointerException.class) - public void testClientDriverNullURI() { - MetadataDrivers.getClientDriver((URI) null); - } - - @Test(expected = NullPointerException.class) - public void testBookieDriverNullURI() { - MetadataDrivers.getBookieDriver((URI) null); - } - - @Test(expected = IllegalArgumentException.class) - public void testClientDriverUnknownScheme() { - MetadataDrivers.getClientDriver("unknown"); - } - - @Test(expected = IllegalArgumentException.class) - public void testBookieDriverUnknownScheme() { - MetadataDrivers.getBookieDriver("unknown"); - } - - @Test(expected = IllegalArgumentException.class) - public void testClientDriverUnknownSchemeURI() { - MetadataDrivers.getClientDriver(URI.create("unknown://")); - } - - @Test(expected = IllegalArgumentException.class) - public void testBookieDriverUnknownSchemeURI() { - MetadataDrivers.getBookieDriver(URI.create("unknown://")); - } - - @Test(expected = NullPointerException.class) - public void testClientDriverNullSchemeURI() { - MetadataDrivers.getClientDriver(URI.create("//127.0.0.1/ledgers")); - } - - @Test(expected = NullPointerException.class) - public void testBookieDriverNullSchemeURI() { - MetadataDrivers.getBookieDriver(URI.create("//127.0.0.1/ledgers")); - } - - @Test - public void testClientDriverLowerUpperCasedSchemes() { - String[] schemes = new String[] { - "zk", "Zk", "zK", "ZK" - }; - for (String scheme : schemes) { - MetadataClientDriver clientDriver = MetadataDrivers.getClientDriver(scheme); - assertEquals( - ZK_CLIENT_DRIVER_CLASS, - clientDriver.getClass().getName()); - } - } - - @Test - public void testBookieDriverLowerUpperCasedSchemes() { - String[] schemes = new String[] { - "zk", "Zk", "zK", "ZK" - }; - for (String scheme : schemes) { - MetadataBookieDriver bookieDriver = MetadataDrivers.getBookieDriver(scheme); - assertEquals( - ZK_BOOKIE_DRIVER_CLASS, - bookieDriver.getClass().getName()); - } - } - - @Test - public void testRegisterClientDriver() throws Exception { - MetadataClientDriver clientDriver = mock(MetadataClientDriver.class); - when(clientDriver.getScheme()).thenReturn("testdriver"); - - try { - MetadataDrivers.getClientDriver(clientDriver.getScheme()); - fail("Should fail to get client driver if it is not registered"); - } catch (IllegalArgumentException iae) { - // expected - } - - MetadataDrivers.registerClientDriver(clientDriver.getScheme(), clientDriver.getClass()); - MetadataClientDriver driver = MetadataDrivers.getClientDriver(clientDriver.getScheme()); - assertEquals(clientDriver.getClass(), driver.getClass()); - } - - @Test - public void testRegisterBookieDriver() throws Exception { - MetadataBookieDriver bookieDriver = mock(MetadataBookieDriver.class); - when(bookieDriver.getScheme()).thenReturn("testdriver"); - - try { - MetadataDrivers.getBookieDriver(bookieDriver.getScheme()); - fail("Should fail to get bookie driver if it is not registered"); - } catch (IllegalArgumentException iae) { - // expected - } - - MetadataDrivers.registerBookieDriver(bookieDriver.getScheme(), bookieDriver.getClass()); - MetadataBookieDriver driver = MetadataDrivers.getBookieDriver(bookieDriver.getScheme()); - assertEquals(bookieDriver.getClass(), driver.getClass()); - } - - @Test - public void testLoadClientDriverFromSystemProperty() throws Exception { - String saveDriversStr = System.getProperty(BK_METADATA_CLIENT_DRIVERS_PROPERTY); - try { - System.setProperty( - BK_METADATA_CLIENT_DRIVERS_PROPERTY, - StringUtils.join(new String[] { - ClientDriver1.class.getName(), - ClientDriver2.class.getName() - }, ':')); - - MetadataDrivers.loadInitialDrivers(); - - MetadataClientDriver loadedDriver1 = MetadataDrivers.getClientDriver("driver1"); - assertEquals(ClientDriver1.class, loadedDriver1.getClass()); - MetadataClientDriver loadedDriver2 = MetadataDrivers.getClientDriver("driver2"); - assertEquals(ClientDriver2.class, loadedDriver2.getClass()); - } finally { - if (null != saveDriversStr) { - System.setProperty(BK_METADATA_CLIENT_DRIVERS_PROPERTY, saveDriversStr); - } else { - System.clearProperty(BK_METADATA_CLIENT_DRIVERS_PROPERTY); - } - } - } - - @Test - public void testLoadBookieDriverFromSystemProperty() throws Exception { - String saveDriversStr = System.getProperty(BK_METADATA_BOOKIE_DRIVERS_PROPERTY); - try { - System.setProperty( - BK_METADATA_BOOKIE_DRIVERS_PROPERTY, - StringUtils.join(new String[] { - BookieDriver1.class.getName(), - BookieDriver2.class.getName() - }, ':')); - - MetadataDrivers.loadInitialDrivers(); - - MetadataBookieDriver loadedDriver1 = MetadataDrivers.getBookieDriver("driver1"); - assertEquals(BookieDriver1.class, loadedDriver1.getClass()); - MetadataBookieDriver loadedDriver2 = MetadataDrivers.getBookieDriver("driver2"); - assertEquals(BookieDriver2.class, loadedDriver2.getClass()); - } finally { - if (null != saveDriversStr) { - System.setProperty(BK_METADATA_BOOKIE_DRIVERS_PROPERTY, saveDriversStr); - } else { - System.clearProperty(BK_METADATA_BOOKIE_DRIVERS_PROPERTY); - } - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MockLedgerManager.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MockLedgerManager.java deleted file mode 100644 index 3704e39e33f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MockLedgerManager.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.meta; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.LedgerMetadataListener; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.Processor; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.zookeeper.AsyncCallback; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Mock implementation of Ledger Manager. - */ -public class MockLedgerManager implements LedgerManager { - static final Logger LOG = LoggerFactory.getLogger(MockLedgerManager.class); - - /** - * Hook for injecting errors or delays. - */ - public interface Hook { - CompletableFuture runHook(long ledgerId, LedgerMetadata metadata); - } - - final Map> metadataMap; - final ExecutorService executor; - final boolean ownsExecutor; - final LedgerMetadataSerDe serDe; - private Hook preWriteHook = (ledgerId, metadata) -> FutureUtils.value(null); - - public MockLedgerManager() { - this(new ConcurrentHashMap<>(), - Executors.newSingleThreadExecutor((r) -> new Thread(r, "MockLedgerManager")), true); - } - - private MockLedgerManager(Map> metadataMap, - ExecutorService executor, boolean ownsExecutor) { - this.metadataMap = metadataMap; - this.executor = executor; - this.ownsExecutor = ownsExecutor; - this.serDe = new LedgerMetadataSerDe(); - } - - public MockLedgerManager newClient() { - return new MockLedgerManager(metadataMap, executor, false); - } - - private Versioned readMetadata(long ledgerId) throws Exception { - Pair pair = metadataMap.get(ledgerId); - if (pair == null) { - return null; - } else { - return new Versioned<>(serDe.parseConfig(pair.getRight(), ledgerId, Optional.empty()), pair.getLeft()); - } - } - - public void setPreWriteHook(Hook hook) { - this.preWriteHook = hook; - } - - public void executeCallback(Runnable r) { - r.run(); - } - - @Override - public CompletableFuture> createLedgerMetadata(long ledgerId, LedgerMetadata metadata) { - CompletableFuture> promise = new CompletableFuture<>(); - executor.submit(() -> { - if (metadataMap.containsKey(ledgerId)) { - executeCallback(() -> promise.completeExceptionally(new BKException.BKLedgerExistException())); - } else { - try { - metadataMap.put(ledgerId, Pair.of(new LongVersion(0L), serDe.serialize(metadata))); - Versioned readBack = readMetadata(ledgerId); - executeCallback(() -> promise.complete(readBack)); - } catch (Exception e) { - LOG.error("Error reading back written metadata", e); - executeCallback(() -> promise.completeExceptionally(new BKException.MetaStoreException())); - } - } - }); - return promise; - } - - @Override - public CompletableFuture removeLedgerMetadata(long ledgerId, Version version) { - return CompletableFuture.completedFuture(null); - } - - @Override - public CompletableFuture> readLedgerMetadata(long ledgerId) { - CompletableFuture> promise = new CompletableFuture<>(); - executor.submit(() -> { - try { - Versioned metadata = readMetadata(ledgerId); - if (metadata == null) { - executeCallback(() -> promise.completeExceptionally( - new BKException.BKNoSuchLedgerExistsOnMetadataServerException())); - } else { - executeCallback(() -> promise.complete(metadata)); - } - } catch (Exception e) { - LOG.error("Error reading metadata", e); - executeCallback(() -> promise.completeExceptionally(new BKException.MetaStoreException())); - } - }); - return promise; - } - - @Override - public CompletableFuture> writeLedgerMetadata(long ledgerId, LedgerMetadata metadata, - Version currentVersion) { - CompletableFuture> promise = new CompletableFuture<>(); - preWriteHook.runHook(ledgerId, metadata) - .thenComposeAsync((ignore) -> { - try { - Versioned oldMetadata = readMetadata(ledgerId); - if (oldMetadata == null) { - return FutureUtils.exception( - new BKException.BKNoSuchLedgerExistsOnMetadataServerException()); - } else if (!oldMetadata.getVersion().equals(currentVersion)) { - return FutureUtils.exception(new BKException.BKMetadataVersionException()); - } else { - LongVersion oldVersion = (LongVersion) oldMetadata.getVersion(); - metadataMap.put(ledgerId, Pair.of(new LongVersion(oldVersion.getLongVersion() + 1), - serDe.serialize(metadata))); - Versioned readBack = readMetadata(ledgerId); - return FutureUtils.value(readBack); - } - } catch (Exception e) { - LOG.error("Error writing metadata", e); - return FutureUtils.exception(e); - } - }, executor) - .whenComplete((res, ex) -> { - if (ex != null) { - Throwable cause = (ex instanceof CompletionException) ? ex.getCause() : ex; - executeCallback(() -> promise.completeExceptionally(cause)); - } else { - executeCallback(() -> promise.complete(res)); - } - }); - return promise; - } - - @Override - public void registerLedgerMetadataListener(long ledgerId, LedgerMetadataListener listener) {} - - @Override - public void unregisterLedgerMetadataListener(long ledgerId, LedgerMetadataListener listener) {} - - @Override - public void asyncProcessLedgers(Processor processor, AsyncCallback.VoidCallback finalCb, - Object context, int successRc, int failureRc) { - } - - @Override - public LedgerRangeIterator getLedgerRanges(long zkOpTimeoutMs) { - List ledgerIds = new ArrayList<>(metadataMap.keySet()); - ledgerIds.sort(Comparator.naturalOrder()); - List> partitions = Lists.partition(ledgerIds, 100); - return new LedgerRangeIterator() { - int i = 0; - @Override - public boolean hasNext() { - if (i >= partitions.size()) { - return false; - } else { - return true; - } - } - - @Override - public LedgerRange next() { - return new LedgerRange(new HashSet<>(partitions.get(i++))); - } - }; - } - - @Override - public void close() { - if (ownsExecutor) { - executor.shutdownNow(); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerLayout.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerLayout.java deleted file mode 100644 index 62315fe2e81..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerLayout.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import org.junit.Test; - -/** - * Unit test of {@link LedgerLayout} class itself. - */ -public class TestLedgerLayout { - - private static final LedgerLayout hierarchical1 = - new LedgerLayout( - HierarchicalLedgerManagerFactory.class.getName(), - 1); - - private static final LedgerLayout hierarchical2 = - new LedgerLayout( - HierarchicalLedgerManagerFactory.class.getName(), - 2); - - private static final LedgerLayout longHierarchical = - new LedgerLayout( - LongHierarchicalLedgerManagerFactory.class.getName(), - 1); - - @Test - public void testEquals() { - assertEquals(hierarchical1, hierarchical1); - assertNotEquals(hierarchical1, hierarchical2); - assertNotEquals(hierarchical1, longHierarchical); - } - - @Test - public void testGetters() { - assertEquals( - HierarchicalLedgerManagerFactory.class.getName(), - hierarchical1.getManagerFactoryClass()); - assertEquals( - 1, - hierarchical1.getManagerVersion()); - assertEquals( - LedgerLayout.LAYOUT_FORMAT_VERSION, - hierarchical1.getLayoutFormatVersion()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerManager.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerManager.java deleted file mode 100644 index a91485a1d32..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerManager.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.meta; - -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CyclicBarrier; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the ledger manager. - */ -public class TestLedgerManager extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestLedgerManager.class); - - public TestLedgerManager() { - super(0); - } - - private void writeLedgerLayout(String ledgersRootPath, - String managerType, - int managerVersion, int layoutVersion) - throws Exception { - LedgerLayout layout = new LedgerLayout(managerType, managerVersion); - - Field f = LedgerLayout.class.getDeclaredField("layoutFormatVersion"); - f.setAccessible(true); - f.set(layout, layoutVersion); - - ZkLayoutManager zkLayoutManager = new ZkLayoutManager(zkc, ledgersRootPath, ZooDefs.Ids.OPEN_ACL_UNSAFE); - zkLayoutManager.storeLedgerLayout(layout); - } - - /** - * Test bad client configuration. - */ - @SuppressWarnings("deprecation") - @Test - public void testBadConf() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - - // success case - String root0 = "/goodconf0"; - zkc.create(root0, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - conf.setZkServers(zkUtil.getZooKeeperConnectString()); - conf.setZkLedgersRootPath(root0); - - ZkLayoutManager zkLayoutManager = new ZkLayoutManager( - zkc, - ZKMetadataDriverBase.resolveZkLedgersRootPath(conf), - ZkUtils.getACLs(conf)); - - LedgerManagerFactory m = AbstractZkLedgerManagerFactory.newLedgerManagerFactory( - conf, - zkLayoutManager); - assertTrue("Ledger manager is unexpected type", - (m instanceof HierarchicalLedgerManagerFactory)); - m.close(); - - // mismatching conf - conf.setLedgerManagerFactoryClass(LongHierarchicalLedgerManagerFactory.class); - try { - AbstractZkLedgerManagerFactory.newLedgerManagerFactory(conf, zkLayoutManager); - fail("Shouldn't reach here"); - } catch (Exception e) { - LOG.error("Received exception", e); - assertTrue("Invalid exception", - e.getMessage().contains("does not match existing layout")); - } - - // invalid ledger manager - String root1 = "/badconf1"; - zkc.create(root1, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - conf.setZkLedgersRootPath(root1); - conf.setLedgerManagerFactoryClassName("DoesNotExist"); - try { - AbstractZkLedgerManagerFactory.newLedgerManagerFactory(conf, zkLayoutManager); - fail("Shouldn't reach here"); - } catch (Exception e) { - LOG.error("Received exception", e); - assertTrue("Invalid exception", - e.getMessage().contains("Failed to retrieve metadata service uri from configuration")); - } - } - - /** - * Test bad client configuration. - */ - @SuppressWarnings("deprecation") - @Test - public void testBadConfV1() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - - String root0 = "/goodconf0"; - zkc.create(root0, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - conf.setMetadataServiceUri(newMetadataServiceUri(root0)); - // write v1 layout - writeLedgerLayout(root0, HierarchicalLedgerManagerFactory.NAME, - HierarchicalLedgerManagerFactory.CUR_VERSION, 1); - - conf.setLedgerManagerFactoryClass(HierarchicalLedgerManagerFactory.class); - - ZkLayoutManager zkLayoutManager = new ZkLayoutManager( - zkc, - ZKMetadataDriverBase.resolveZkLedgersRootPath(conf), - ZkUtils.getACLs(conf)); - - LedgerManagerFactory m = AbstractZkLedgerManagerFactory.newLedgerManagerFactory( - conf, - zkLayoutManager); - - assertTrue("Ledger manager is unexpected type", - (m instanceof HierarchicalLedgerManagerFactory)); - m.close(); - - // v2 setting doesn't effect v1 - conf.setLedgerManagerFactoryClass(HierarchicalLedgerManagerFactory.class); - m = AbstractZkLedgerManagerFactory.newLedgerManagerFactory(conf, zkLayoutManager); - assertTrue("Ledger manager is unexpected type", - (m instanceof HierarchicalLedgerManagerFactory)); - m.close(); - - // mismatching conf - conf.setLedgerManagerType(LongHierarchicalLedgerManagerFactory.NAME); - try { - AbstractZkLedgerManagerFactory.newLedgerManagerFactory(conf, zkLayoutManager); - fail("Shouldn't reach here"); - } catch (Exception e) { - LOG.error("Received exception", e); - assertTrue("Invalid exception", - e.getMessage().contains("does not match existing layout")); - } - } - - /** - * Test bad zk configuration. - */ - @Test - public void testBadZkContents() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - - // bad type in zookeeper - String root0 = "/badzk0"; - zkc.create(root0, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - conf.setMetadataServiceUri(newMetadataServiceUri(root0, HierarchicalLedgerManagerFactory.NAME)); - - LedgerLayout layout = new LedgerLayout("DoesNotExist", - 0xdeadbeef); - - ZkLayoutManager zkLayoutManager = new ZkLayoutManager(zkc, root0, ZooDefs.Ids.OPEN_ACL_UNSAFE); - zkLayoutManager.storeLedgerLayout(layout); - - try { - AbstractZkLedgerManagerFactory.newLedgerManagerFactory(conf, zkLayoutManager); - fail("Shouldn't reach here"); - } catch (Exception e) { - LOG.error("Received exception", e); - assertTrue("Invalid exception", e.getMessage().contains( - "Configured layout org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory" - + " does not match existing layout DoesNotExist")); - } - - // bad version in zookeeper - String root1 = "/badzk1"; - zkc.create(root1, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - conf.setMetadataServiceUri(newMetadataServiceUri(root1)); - - LedgerLayout layout1 = new LedgerLayout(HierarchicalLedgerManagerFactory.class.getName(), - 0xdeadbeef); - ZkLayoutManager zkLayoutManager1 = new ZkLayoutManager(zkc, root1, ZooDefs.Ids.OPEN_ACL_UNSAFE); - zkLayoutManager1.storeLedgerLayout(layout1); - - try { - AbstractZkLedgerManagerFactory.newLedgerManagerFactory(conf, zkLayoutManager1); - fail("Shouldn't reach here"); - } catch (Exception e) { - LOG.error("Received exception", e); - assertTrue("Invalid exception", - e.getMessage().contains("Incompatible layout version found")); - } - } - - private static class CreateLMThread extends Thread { - private boolean success = false; - private final String factoryCls; - private final CyclicBarrier barrier; - private ZooKeeper zkc; - private ClientConfiguration conf; - - @SuppressWarnings("deprecation") - CreateLMThread(String zkConnectString, String root, - String factoryCls, CyclicBarrier barrier) throws Exception { - this.factoryCls = factoryCls; - this.barrier = barrier; - zkc = ZooKeeperClient.newBuilder() - .connectString(zkConnectString) - .build(); - this.conf = new ClientConfiguration(); - conf.setZkServers(zkConnectString); - conf.setZkLedgersRootPath(root); - } - - public void run() { - conf.setLedgerManagerFactoryClassName(factoryCls); - - try { - barrier.await(); - runFunctionWithLedgerManagerFactory(new ServerConfiguration(conf), factory -> null); - success = true; - } catch (Exception e) { - LOG.error("Failed to create ledger manager", e); - } - } - - public boolean isSuccessful() { - return success; - } - - public void close() throws Exception { - zkc.close(); - } - } - - // test concurrent - @Test - public void testConcurrent1() throws Exception { - /// everyone creates the same - int numThreads = 50; - - // bad version in zookeeper - String root0 = "/lmroot0"; - zkc.create(root0, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - CyclicBarrier barrier = new CyclicBarrier(numThreads + 1); - List threads = new ArrayList(numThreads); - for (int i = 0; i < numThreads; i++) { - CreateLMThread t = new CreateLMThread(zkUtil.getZooKeeperConnectString(), - root0, HierarchicalLedgerManagerFactory.class.getName(), barrier); - t.start(); - threads.add(t); - } - - barrier.await(); - - boolean success = true; - for (CreateLMThread t : threads) { - t.join(); - t.close(); - success = t.isSuccessful() && success; - } - assertTrue("Not all ledger managers created", success); - } - - @Test - public void testConcurrent2() throws Exception { - /// odd create different - int numThreadsEach = 25; - - // bad version in zookeeper - String root0 = "/lmroot0"; - zkc.create(root0, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - CyclicBarrier barrier = new CyclicBarrier(numThreadsEach * 2 + 1); - List threadsA = new ArrayList(numThreadsEach); - for (int i = 0; i < numThreadsEach; i++) { - CreateLMThread t = new CreateLMThread(zkUtil.getZooKeeperConnectString(), - root0, HierarchicalLedgerManagerFactory.class.getName(), barrier); - t.start(); - threadsA.add(t); - } - List threadsB = new ArrayList(numThreadsEach); - for (int i = 0; i < numThreadsEach; i++) { - CreateLMThread t = new CreateLMThread(zkUtil.getZooKeeperConnectString(), - root0, LongHierarchicalLedgerManagerFactory.class.getName(), barrier); - t.start(); - threadsB.add(t); - } - - barrier.await(); - - int numSuccess = 0; - int numFails = 0; - for (CreateLMThread t : threadsA) { - t.join(); - t.close(); - if (t.isSuccessful()) { - numSuccess++; - } else { - numFails++; - } - } - - for (CreateLMThread t : threadsB) { - t.join(); - t.close(); - if (t.isSuccessful()) { - numSuccess++; - } else { - numFails++; - } - } - assertEquals("Incorrect number of successes", numThreadsEach, numSuccess); - assertEquals("Incorrect number of failures", numThreadsEach, numFails); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerMetadataSerDe.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerMetadataSerDe.java deleted file mode 100644 index be2a0f34a8c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerMetadataSerDe.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.collect.Lists; -import java.io.IOException; -import java.util.Base64; -import java.util.Optional; -import java.util.Random; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test Ledger Metadata serialization and deserialization. - */ -public class TestLedgerMetadataSerDe { - // as used in 4.0.x & 4.1.x - private static final String version1 = - "Qm9va2llTWV0YWRhdGFGb3JtYXRWZXJzaW9uCTEKMgozCjAKMAkxOTIuMC4yLjE6MTIzNAkxOTIu" - + "MC4yLjI6MTIzNAkxOTIuMC4yLjM6MTIzNAotMTAyCUNMT1NFRA=="; - - // as used in 4.2.x & 4.3.x (text protobuf based metadata, password and digest introduced) - private static final String version2 = - "Qm9va2llTWV0YWRhdGFGb3JtYXRWZXJzaW9uCTIKcXVvcnVtU2l6ZTogMgplbnNlbWJsZVNpemU6I" - + "DMKbGVuZ3RoOiAwCmxhc3RFbnRyeUlkOiAtMQpzdGF0ZTogSU5fUkVDT1ZFUlkKc2VnbWVudCB7" - + "CiAgZW5zZW1ibGVNZW1iZXI6ICIxOTIuMC4yLjE6MTIzNCIKICBlbnNlbWJsZU1lbWJlcjogIjE" - + "5Mi4wLjIuMjoxMjM0IgogIGVuc2VtYmxlTWVtYmVyOiAiMTkyLjAuMi4zOjEyMzQiCiAgZmlyc3" - + "RFbnRyeUlkOiAwCn0KZGlnZXN0VHlwZTogQ1JDMzIKcGFzc3dvcmQ6ICJwYXNzd2QiCmFja1F1b" - + "3J1bVNpemU6IDIK"; - - // version 2 + ctime, as used in 4.4.x to 4.8.x (ctime is optional from 4.6.x onwards) - private static final String version2ctime = - "Qm9va2llTWV0YWRhdGFGb3JtYXRWZXJzaW9uCTIKcXVvcnVtU2l6ZTogMgplbnNlbWJsZVNpemU6I" - + "DMKbGVuZ3RoOiAwCmxhc3RFbnRyeUlkOiAtMQpzdGF0ZTogSU5fUkVDT1ZFUlkKc2VnbWVudCB7" - + "CiAgZW5zZW1ibGVNZW1iZXI6ICIxOTIuMC4yLjE6MTIzNCIKICBlbnNlbWJsZU1lbWJlcjogIjE" - + "5Mi4wLjIuMjoxMjM0IgogIGVuc2VtYmxlTWVtYmVyOiAiMTkyLjAuMi4zOjEyMzQiCiAgZmlyc3" - + "RFbnRyeUlkOiAwCn0KZGlnZXN0VHlwZTogQ1JDMzIKcGFzc3dvcmQ6ICJwYXNzd2QiCmFja1F1b" - + "3J1bVNpemU6IDIKY3RpbWU6IDE1NDQwMDIzODMwNzUK"; - - // version 3, since 4.9.x, protobuf binary format - private static final String version3 = - "Qm9va2llTWV0YWRhdGFGb3JtYXRWZXJzaW9uCTMKYAgCEAMYACD///////////8BKAEyMgoOMTkyL" - + "jAuMi4xOjMxODEKDjE5Mi4wLjIuMjozMTgxCg4xOTIuMC4yLjM6MzE4MRAAOANCBmZvb2JhckgB" - + "UP///////////wFgAA=="; - - private static void testDecodeEncode(String encoded) throws Exception { - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - LedgerMetadata md = serDe.parseConfig(Base64.getDecoder().decode(encoded), 59L, Optional.empty()); - String reserialized = Base64.getEncoder().encodeToString(serDe.serialize(md)); - - Assert.assertEquals(encoded, reserialized); - } - - @Test - public void testVersion1SerDe() throws Exception { - testDecodeEncode(version1); - } - - @Test - public void testVersion2SerDe() throws Exception { - testDecodeEncode(version2); - } - - @Test - public void testVersion2CtimeSerDe() throws Exception { - testDecodeEncode(version2ctime); - } - - @Test - public void testVersion3SerDe() throws Exception { - testDecodeEncode(version3); - } - - @Test(expected = IOException.class) - public void testJunkSerDe() throws Exception { - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - String junk = ""; - serDe.parseConfig(junk.getBytes(UTF_8), 59L, Optional.empty()); - } - - @Test(expected = IOException.class) - public void testJunk2SerDe() throws Exception { - byte[] randomBytes = new byte[1000]; - new Random().nextBytes(randomBytes); - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - serDe.parseConfig(randomBytes, 59L, Optional.empty()); - } - - @Test(expected = IOException.class) - public void testJunkVersionSerDe() throws Exception { - byte[] junkVersion = "BookieMetadataFormatVersion\tfoobar\nblahblah".getBytes(UTF_8); - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - serDe.parseConfig(junkVersion, 59L, Optional.empty()); - } - - @Test(expected = IOException.class) - public void testVeryLongVersionSerDe() throws Exception { - byte[] veryLongVersion = "BookieMetadataFormatVersion\t123456789123456789\nblahblah".getBytes(UTF_8); - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - serDe.parseConfig(veryLongVersion, 59L, Optional.empty()); - } - - @Test - public void testPeggedToV3SerDe() throws Exception { - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - LedgerMetadata metadata = LedgerMetadataBuilder.create().withId(13L) - .withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(1) - .withPassword("foobar".getBytes(UTF_8)).withDigestType(DigestType.CRC32C) - .newEnsembleEntry(0L, Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 3181).toBookieId(), - new BookieSocketAddress("192.0.2.2", 3181).toBookieId(), - new BookieSocketAddress("192.0.2.3", 3181).toBookieId())) - .build(); - byte[] encoded = serDe.serialize(metadata); - - LedgerMetadata decoded = serDe.parseConfig(encoded, 59L, Optional.empty()); - Assert.assertEquals(LedgerMetadataSerDe.METADATA_FORMAT_VERSION_3, decoded.getMetadataFormatVersion()); - } - - @Test - public void testStoreSystemtimeAsLedgerCtimeEnabledWithNewerVersion() - throws Exception { - LedgerMetadata lm = LedgerMetadataBuilder.create().withId(13L) - .withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(1) - .withPassword("foobar".getBytes(UTF_8)).withDigestType(DigestType.CRC32C) - .newEnsembleEntry(0L, Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId())) - .withCreationTime(123456L) - .storingCreationTime(true) - .build(); - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - byte[] serialized = serDe.serialize(lm); - LedgerMetadata deserialized = serDe.parseConfig(serialized, 59L, Optional.of(654321L)); - Assert.assertEquals(deserialized.getCtime(), 123456L); - - // give it another round - LedgerMetadata deserialized2 = serDe.parseConfig(serDe.serialize(deserialized), 59L, Optional.of(98765L)); - Assert.assertEquals(deserialized2.getCtime(), 123456L); - } - - @Test - public void testStoreSystemtimeAsLedgerCtimeDisabledWithNewerVersion() - throws Exception { - LedgerMetadata lm = LedgerMetadataBuilder.create().withId(13L) - .withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(1) - .withPassword("foobar".getBytes(UTF_8)).withDigestType(DigestType.CRC32C) - .newEnsembleEntry(0L, Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId())) - .build(); - LedgerMetadataSerDe serDe = new LedgerMetadataSerDe(); - byte[] serialized = serDe.serialize(lm); - LedgerMetadata deserialized = serDe.parseConfig(serialized, 59L, Optional.of(654321L)); - Assert.assertEquals(654321L, deserialized.getCtime()); - - // give it another round - LedgerMetadata deserialized2 = serDe.parseConfig(serDe.serialize(deserialized), 59L, Optional.of(98765L)); - Assert.assertEquals(98765L, deserialized2.getCtime()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLongZkLedgerIdGenerator.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLongZkLedgerIdGenerator.java deleted file mode 100644 index b409cc6b2fa..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLongZkLedgerIdGenerator.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import junit.framework.TestCase; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException.Code; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test ZK ledger id generator of long values. - */ -public class TestLongZkLedgerIdGenerator extends TestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestZkLedgerIdGenerator.class); - - ZooKeeperUtil zkutil; - ZooKeeper zk; - - LongZkLedgerIdGenerator ledgerIdGenerator; - - @Override - @Before - public void setUp() throws Exception { - LOG.info("Setting up test"); - super.setUp(); - - zkutil = new ZooKeeperUtil(); - zkutil.startCluster(); - zk = zkutil.getZooKeeperClient(); - - ZkLedgerIdGenerator shortLedgerIdGenerator = new ZkLedgerIdGenerator(zk, - "/test-zk-ledger-id-generator", "idgen", ZooDefs.Ids.OPEN_ACL_UNSAFE); - ledgerIdGenerator = new LongZkLedgerIdGenerator(zk, - "/test-zk-ledger-id-generator", "idgen-long", shortLedgerIdGenerator, ZooDefs.Ids.OPEN_ACL_UNSAFE); - } - - @Override - @After - public void tearDown() throws Exception { - LOG.info("Tearing down test"); - ledgerIdGenerator.close(); - zk.close(); - zkutil.killCluster(); - - super.tearDown(); - } - - @Test - public void testGenerateLedgerId() throws Exception { - // Create *nThread* threads each generate *nLedgers* ledger id, - // and then check there is no identical ledger id. - final int nThread = 2; - final int nLedgers = 2000; - // Multiply by two. We're going to do half in the old legacy space and half in the new. - final CountDownLatch countDownLatch = new CountDownLatch(nThread * nLedgers * 2); - - final AtomicInteger errCount = new AtomicInteger(0); - final ConcurrentLinkedQueue ledgerIds = new ConcurrentLinkedQueue(); - final GenericCallback cb = new GenericCallback() { - @Override - public void operationComplete(int rc, Long result) { - if (Code.OK.intValue() == rc) { - ledgerIds.add(result); - } else { - errCount.incrementAndGet(); - } - countDownLatch.countDown(); - } - }; - - long start = System.currentTimeMillis(); - - for (int i = 0; i < nThread; i++) { - new Thread() { - @Override - public void run() { - for (int j = 0; j < nLedgers; j++) { - ledgerIdGenerator.generateLedgerId(cb); - } - } - }.start(); - } - - // Go and create the long-id directory in zookeeper. This should cause the id generator to generate ids with the - // new algo once we clear it's stored status. - ZkUtils.createFullPathOptimistic(zk, "/test-zk-ledger-id-generator/idgen-long", new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - ledgerIdGenerator.invalidateLedgerIdGenPathStatus(); - - for (int i = 0; i < nThread; i++) { - new Thread() { - @Override - public void run() { - for (int j = 0; j < nLedgers; j++) { - ledgerIdGenerator.generateLedgerId(cb); - } - } - }.start(); - } - - assertTrue("Wait ledger id generation threads to stop timeout : ", - countDownLatch.await(120, TimeUnit.SECONDS)); - LOG.info("Number of generated ledger id: {}, time used: {}", ledgerIds.size(), - System.currentTimeMillis() - start); - assertEquals("Error occur during ledger id generation : ", 0, errCount.get()); - - Set ledgers = new HashSet(); - while (!ledgerIds.isEmpty()) { - Long ledger = ledgerIds.poll(); - assertNotNull("Generated ledger id is null : ", ledger); - assertFalse("Ledger id [" + ledger + "] conflict : ", ledgers.contains(ledger)); - ledgers.add(ledger); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLayoutManager.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLayoutManager.java deleted file mode 100644 index ab09f611c7f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLayoutManager.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta; - -import static org.apache.bookkeeper.util.BookKeeperConstants.LAYOUT_ZNODE; -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.junit.Test; - -/** - * Unit test of {@link ZkLayoutManager}. - */ -public class TestZkLayoutManager { - - private static final String ledgersRootPath = "/path/to/ledgers/root"; - private static final String layoutPath = ledgersRootPath + "/" + LAYOUT_ZNODE; - private static final int managerVersion = 78; - - private final ZooKeeper zk; - private final LedgerLayout layout; - private final ZkLayoutManager zkLayoutManager; - - public TestZkLayoutManager() { - this.zk = mock(ZooKeeper.class); - this.layout = new LedgerLayout( - HierarchicalLedgerManagerFactory.class.getName(), - managerVersion); - this.zkLayoutManager = new ZkLayoutManager(zk, ledgersRootPath, Ids.OPEN_ACL_UNSAFE); - } - - @Test - public void testReadLayout() throws Exception { - when(zk.getData(eq(layoutPath), eq(false), eq(null))) - .thenReturn(layout.serialize()); - - assertEquals(layout, zkLayoutManager.readLedgerLayout()); - } - - @Test - public void testStoreLayout() throws Exception { - zkLayoutManager.storeLedgerLayout(layout); - - verify(zk, times(1)) - .create(eq(layoutPath), eq(layout.serialize()), eq(Ids.OPEN_ACL_UNSAFE), eq(CreateMode.PERSISTENT)); - } - - @Test - public void testDeleteLayout() throws Exception { - zkLayoutManager.deleteLedgerLayout(); - - verify(zk, times(1)) - .delete(eq(layoutPath), eq(-1)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLedgerIdGenerator.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLedgerIdGenerator.java deleted file mode 100644 index 44c739334aa..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLedgerIdGenerator.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import junit.framework.TestCase; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.zookeeper.KeeperException.Code; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the ZK ledger id generator. - */ -public class TestZkLedgerIdGenerator extends TestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestZkLedgerIdGenerator.class); - - ZooKeeperUtil zkutil; - ZooKeeper zk; - - LedgerIdGenerator ledgerIdGenerator; - - @Override - @Before - public void setUp() throws Exception { - LOG.info("Setting up test"); - super.setUp(); - - zkutil = new ZooKeeperUtil(); - zkutil.startCluster(); - zk = zkutil.getZooKeeperClient(); - - ledgerIdGenerator = new ZkLedgerIdGenerator(zk, - "/test-zk-ledger-id-generator", "idgen", ZooDefs.Ids.OPEN_ACL_UNSAFE); - } - - @Override - @After - public void tearDown() throws Exception { - LOG.info("Tearing down test"); - ledgerIdGenerator.close(); - zk.close(); - zkutil.killCluster(); - - super.tearDown(); - } - - @Test - public void testGenerateLedgerId() throws Exception { - // Create *nThread* threads each generate *nLedgers* ledger id, - // and then check there is no identical ledger id. - final int nThread = 2; - final int nLedgers = 2000; - final CountDownLatch countDownLatch = new CountDownLatch(nThread * nLedgers); - - final AtomicInteger errCount = new AtomicInteger(0); - final ConcurrentLinkedQueue ledgerIds = new ConcurrentLinkedQueue(); - final GenericCallback cb = new GenericCallback() { - @Override - public void operationComplete(int rc, Long result) { - if (Code.OK.intValue() == rc) { - ledgerIds.add(result); - } else { - errCount.incrementAndGet(); - } - countDownLatch.countDown(); - } - }; - - long start = System.currentTimeMillis(); - - for (int i = 0; i < nThread; i++) { - new Thread() { - @Override - public void run() { - for (int j = 0; j < nLedgers; j++) { - ledgerIdGenerator.generateLedgerId(cb); - } - } - }.start(); - } - - assertTrue("Wait ledger id generation threads to stop timeout : ", - countDownLatch.await(30, TimeUnit.SECONDS)); - LOG.info("Number of generated ledger id: {}, time used: {}", ledgerIds.size(), - System.currentTimeMillis() - start); - assertEquals("Error occur during ledger id generation : ", 0, errCount.get()); - - Set ledgers = new HashSet(); - while (!ledgerIds.isEmpty()) { - Long ledger = ledgerIds.poll(); - assertNotNull("Generated ledger id is null : ", ledger); - assertFalse("Ledger id [" + ledger + "] conflict : ", ledgers.contains(ledger)); - ledgers.add(ledger); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/ZkLedgerLayoutTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/ZkLedgerLayoutTest.java deleted file mode 100644 index cfe5a686ebd..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/ZkLedgerLayoutTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.meta; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.lang.reflect.Field; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs.Ids; -import org.junit.Test; - -/** - * Test store/read/delete ledger layout operations on zookeeper. - */ -public class ZkLedgerLayoutTest extends BookKeeperClusterTestCase { - - public ZkLedgerLayoutTest() { - super(0); - } - - protected ClientConfiguration newClientConfiguration() { - return new ClientConfiguration() - .setMetadataServiceUri(metadataServiceUri); - } - - @Test - public void testLedgerLayout() throws Exception { - ClientConfiguration conf = newClientConfiguration(); - conf.setLedgerManagerFactoryClass(HierarchicalLedgerManagerFactory.class); - String ledgerRootPath = "/testLedgerLayout"; - ZkLayoutManager zkLayoutManager = new ZkLayoutManager(zkc, ledgerRootPath, Ids.OPEN_ACL_UNSAFE); - - zkc.create(ledgerRootPath, new byte[0], - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - assertEquals(null, zkLayoutManager.readLedgerLayout()); - - String testName = "foobar"; - int testVersion = 0xdeadbeef; - // use layout defined in configuration also create it in zookeeper - LedgerLayout layout2 = new LedgerLayout(testName, testVersion); - zkLayoutManager.storeLedgerLayout(layout2); - - LedgerLayout layout = zkLayoutManager.readLedgerLayout(); - assertEquals(testName, layout.getManagerFactoryClass()); - assertEquals(testVersion, layout.getManagerVersion()); - } - - private void writeLedgerLayout( - String ledgersRootPath, - String managerType, - int managerVersion, int layoutVersion) - throws Exception { - LedgerLayout layout = new LedgerLayout(managerType, managerVersion); - - Field f = LedgerLayout.class.getDeclaredField("layoutFormatVersion"); - f.setAccessible(true); - f.set(layout, layoutVersion); - ZkLayoutManager zkLayoutManager = new ZkLayoutManager(zkc, ledgersRootPath, Ids.OPEN_ACL_UNSAFE); - - zkLayoutManager.storeLedgerLayout(layout); - } - - @Test - public void testBadVersionLedgerLayout() throws Exception { - ClientConfiguration conf = newClientConfiguration(); - String zkLedgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf); - // write bad version ledger layout - writeLedgerLayout(zkLedgersRootPath, - HierarchicalLedgerManagerFactory.class.getName(), - HierarchicalLedgerManagerFactory.CUR_VERSION, - LedgerLayout.LAYOUT_FORMAT_VERSION + 1); - - ZkLayoutManager zkLayoutManager = new ZkLayoutManager(zkc, zkLedgersRootPath, Ids.OPEN_ACL_UNSAFE); - - try { - zkLayoutManager.readLedgerLayout(); - fail("Shouldn't reach here!"); - } catch (IOException ie) { - assertTrue("Invalid exception", ie.getMessage().contains("version not compatible")); - } - } - - @Test - public void testAbsentLedgerManagerLayout() throws Exception { - ClientConfiguration conf = newClientConfiguration(); - String ledgersLayout = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf) + "/" - + BookKeeperConstants.LAYOUT_ZNODE; - // write bad format ledger layout - StringBuilder sb = new StringBuilder(); - sb.append(LedgerLayout.LAYOUT_FORMAT_VERSION).append("\n"); - zkc.create(ledgersLayout, sb.toString().getBytes(), - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - ZkLayoutManager zkLayoutManager = new ZkLayoutManager( - zkc, ZKMetadataDriverBase.resolveZkLedgersRootPath(conf), Ids.OPEN_ACL_UNSAFE); - - try { - zkLayoutManager.readLedgerLayout(); - fail("Shouldn't reach here!"); - } catch (IOException ie) { - assertTrue("Invalid exception", ie.getMessage().contains("version absent from")); - } - } - - @Test - public void testBaseLedgerManagerLayout() throws Exception { - ClientConfiguration conf = newClientConfiguration(); - String rootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf); - String ledgersLayout = rootPath + "/" - + BookKeeperConstants.LAYOUT_ZNODE; - // write bad format ledger layout - StringBuilder sb = new StringBuilder(); - sb.append(LedgerLayout.LAYOUT_FORMAT_VERSION).append("\n") - .append(HierarchicalLedgerManagerFactory.class.getName()); - zkc.create(ledgersLayout, sb.toString().getBytes(), - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - ZkLayoutManager zkLayoutManager = new ZkLayoutManager(zkc, rootPath, Ids.OPEN_ACL_UNSAFE); - - try { - zkLayoutManager.readLedgerLayout(); - fail("Shouldn't reach here!"); - } catch (IOException ie) { - assertTrue("Invalid exception", ie.getMessage().contains("Invalid Ledger Manager")); - } - } - - @Test - public void testReadV1LedgerManagerLayout() throws Exception { - ClientConfiguration conf = newClientConfiguration(); - String zkLedgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf); - // write v1 ledger layout - writeLedgerLayout(zkLedgersRootPath, - HierarchicalLedgerManagerFactory.NAME, - HierarchicalLedgerManagerFactory.CUR_VERSION, 1); - ZkLayoutManager zkLayoutManager = new ZkLayoutManager(zkc, zkLedgersRootPath, Ids.OPEN_ACL_UNSAFE); - - LedgerLayout layout = zkLayoutManager.readLedgerLayout(); - - assertNotNull("Should not be null", layout); - assertEquals(HierarchicalLedgerManagerFactory.NAME, layout.getManagerFactoryClass()); - assertEquals(HierarchicalLedgerManagerFactory.CUR_VERSION, layout.getManagerVersion()); - assertEquals(1, layout.getLayoutFormatVersion()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataBookieDriverTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataBookieDriverTest.java deleted file mode 100644 index de2e9f9fdc7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataBookieDriverTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta.zk; - -import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.discover.ZKRegistrationManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test {@link ZKMetadataBookieDriver}. - */ -@RunWith(MockitoJUnitRunner.class) -public class ZKMetadataBookieDriverTest extends ZKMetadataDriverTestBase { - - private ZKMetadataBookieDriver driver; - private ServerConfiguration conf; - - @Before - public void setup() throws Exception { - this.conf = new ServerConfiguration(); - super.setup(conf); - - driver = spy(new ZKMetadataBookieDriver()); - } - - @After - public void teardown() { - super.teardown(); - driver.close(); - } - - @Test - public void testGetRegManager() throws Exception { - driver.initialize(conf, NullStatsLogger.INSTANCE); - - assertSame(conf, driver.serverConf); - - ZKRegistrationManager mockRegManager = mock(ZKRegistrationManager.class); - doReturn(mockRegManager).when(driver).newZKRegistrationManager(any(ServerConfiguration.class), - any(ZooKeeper.class)); - - try (RegistrationManager manager = driver.createRegistrationManager()) { - assertSame(mockRegManager, manager); - - verify(driver, times(1)).newZKRegistrationManager(same(conf), same(mockZkc)); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriverTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriverTest.java deleted file mode 100644 index 8b9ed9905d6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriverTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta.zk; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.Optional; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.discover.RegistrationClient; -import org.apache.bookkeeper.discover.ZKRegistrationClient; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.zookeeper.ZooKeeper; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test {@link ZKMetadataClientDriver}. - */ -@RunWith(MockitoJUnitRunner.class) -public class ZKMetadataClientDriverTest extends ZKMetadataDriverTestBase { - - private ZKMetadataClientDriver driver; - private ClientConfiguration conf; - - @Before - public void setup() throws Exception { - this.conf = new ClientConfiguration(); - super.setup(conf); - - driver = spy(new ZKMetadataClientDriver()); - } - - @Test - public void testGetRegClient() throws Exception { - ScheduledExecutorService mockExecutor = mock(ScheduledExecutorService.class); - driver.initialize(conf, mockExecutor, NullStatsLogger.INSTANCE, Optional.empty()); - - assertSame(conf, driver.clientConf); - assertSame(mockExecutor, driver.scheduler); - assertNull(driver.regClient); - - ZKRegistrationClient mockRegClient = mock(ZKRegistrationClient.class); - - doReturn(mockRegClient).when(driver).newZKRegistrationClient(any(ZooKeeper.class), - anyString(), any(ScheduledExecutorService.class), anyBoolean()); - - RegistrationClient client = driver.getRegistrationClient(); - assertSame(mockRegClient, client); - assertSame(mockRegClient, driver.regClient); - - verify(driver, times(1)).newZKRegistrationClient(eq(mockZkc), - eq(ledgersRootPath), eq(mockExecutor), anyBoolean()); - - driver.close(); - verify(mockRegClient, times(1)).close(); - assertNull(driver.regClient); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseStaticTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseStaticTest.java deleted file mode 100644 index 66b096172bc..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseStaticTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta.zk; - -import static org.junit.Assert.assertEquals; - -import java.net.URI; -import org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.meta.LongHierarchicalLedgerManagerFactory; -import org.junit.Test; - -/** - * Unit test the static methods of {@link ZKMetadataDriverBase}. - */ -public class ZKMetadataDriverBaseStaticTest { - - @Test - public void testGetZKServersFromServiceUri() { - String uriStr = "zk://server1;server2;server3/ledgers"; - URI uri = URI.create(uriStr); - - String zkServers = ZKMetadataDriverBase.getZKServersFromServiceUri(uri); - assertEquals( - "server1,server2,server3", - zkServers); - - uriStr = "zk://server1,server2,server3/ledgers"; - uri = URI.create(uriStr); - zkServers = ZKMetadataDriverBase.getZKServersFromServiceUri(uri); - assertEquals( - "server1,server2,server3", - zkServers); - } - - @Test(expected = NullPointerException.class) - public void testResolveLedgerManagerFactoryNullUri() { - ZKMetadataDriverBase.resolveLedgerManagerFactory(null); - } - - @Test(expected = NullPointerException.class) - public void testResolveLedgerManagerFactoryNullScheme() { - ZKMetadataDriverBase.resolveLedgerManagerFactory(URI.create("//127.0.0.1/ledgers")); - } - - @Test(expected = IllegalArgumentException.class) - public void testResolveLedgerManagerFactoryUnknownScheme() { - ZKMetadataDriverBase.resolveLedgerManagerFactory(URI.create("unknown://127.0.0.1/ledgers")); - } - - @Test - public void testResolveLedgerManagerFactoryUnspecifiedLayout() { - assertEquals( - null, - ZKMetadataDriverBase.resolveLedgerManagerFactory( - URI.create("zk://127.0.0.1/ledgers")) - ); - } - - @Test - public void testResolveLedgerManagerFactoryNullLayout() { - assertEquals( - null, - ZKMetadataDriverBase.resolveLedgerManagerFactory( - URI.create("zk+null://127.0.0.1/ledgers")) - ); - } - - @SuppressWarnings("deprecation") - @Test - public void testResolveLedgerManagerFactoryFlat() { - assertEquals( - org.apache.bookkeeper.meta.FlatLedgerManagerFactory.class, - ZKMetadataDriverBase.resolveLedgerManagerFactory( - URI.create("zk+flat://127.0.0.1/ledgers")) - ); - } - - @SuppressWarnings("deprecation") - @Test - public void testResolveLedgerManagerFactoryMs() { - assertEquals( - org.apache.bookkeeper.meta.MSLedgerManagerFactory.class, - ZKMetadataDriverBase.resolveLedgerManagerFactory( - URI.create("zk+ms://127.0.0.1/ledgers")) - ); - } - - @Test - public void testResolveLedgerManagerFactoryHierarchical() { - assertEquals( - HierarchicalLedgerManagerFactory.class, - ZKMetadataDriverBase.resolveLedgerManagerFactory( - URI.create("zk+hierarchical://127.0.0.1/ledgers")) - ); - } - - @Test - public void testResolveLedgerManagerFactoryLongHierarchical() { - assertEquals( - LongHierarchicalLedgerManagerFactory.class, - ZKMetadataDriverBase.resolveLedgerManagerFactory( - URI.create("zk+longhierarchical://127.0.0.1/ledgers")) - ); - } - - @Test(expected = IllegalArgumentException.class) - public void testResolveLedgerManagerFactoryUnknownLedgerManagerFactory() { - ZKMetadataDriverBase.resolveLedgerManagerFactory( - URI.create("zk+unknown://127.0.0.1/ledgers")); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseTest.java deleted file mode 100644 index 3a387d15960..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseTest.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta.zk; - -import static org.apache.bookkeeper.util.BookKeeperConstants.AVAILABLE_NODE; -import static org.apache.bookkeeper.util.BookKeeperConstants.READONLY; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.Optional; -import lombok.Cleanup; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.AbstractZkLedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.zookeeper.RetryPolicy; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test of {@link ZKMetadataDriverBase}. - */ -@RunWith(MockitoJUnitRunner.class) -public class ZKMetadataDriverBaseTest extends ZKMetadataDriverTestBase { - - private ZKMetadataDriverBase driver; - private RetryPolicy retryPolicy; - - @Before - public void setup() throws Exception { - super.setup(new ClientConfiguration()); - driver = mock(ZKMetadataDriverBase.class, CALLS_REAL_METHODS); - retryPolicy = mock(RetryPolicy.class); - } - - @After - public void teardown() { - super.teardown(); - } - - @Test - public void testInitialize() throws Exception { - driver.initialize( - conf, NullStatsLogger.INSTANCE, retryPolicy, Optional.empty()); - - assertEquals( - "/path/to/ledgers", - driver.ledgersRootPath); - assertTrue(driver.ownZKHandle); - - String readonlyPath = "/path/to/ledgers/" + AVAILABLE_NODE + "/" + READONLY; - assertSame(mockZkc, driver.zk); - - ZooKeeperClient.newBuilder(); - verify(mockZkBuilder, times(1)).build(); - verify(mockZkc, times(1)) - .exists(eq(readonlyPath), eq(false)); - assertNotNull(driver.layoutManager); - assertNull(driver.lmFactory); - - driver.close(); - - verify(mockZkc, times(1)).close(5000); - assertNull(driver.zk); - } - - @Test - public void testInitializeExternalZooKeeper() throws Exception { - ZooKeeperClient anotherZk = mock(ZooKeeperClient.class); - - driver.initialize( - conf, NullStatsLogger.INSTANCE, retryPolicy, Optional.of(anotherZk)); - - assertEquals( - "/ledgers", - driver.ledgersRootPath); - assertFalse(driver.ownZKHandle); - - String readonlyPath = "/path/to/ledgers/" + AVAILABLE_NODE; - assertSame(anotherZk, driver.zk); - - ZooKeeperClient.newBuilder(); - verify(mockZkBuilder, times(0)).build(); - verify(mockZkc, times(0)) - .exists(eq(readonlyPath), eq(false)); - assertNotNull(driver.layoutManager); - assertNull(driver.lmFactory); - - driver.close(); - - verify(mockZkc, times(0)).close(); - assertNotNull(driver.zk); - } - - @Test - public void testGetLedgerManagerFactory() throws Exception { - driver.initialize( - conf, NullStatsLogger.INSTANCE, retryPolicy, Optional.empty()); - - @Cleanup - MockedStatic abstractZkLedgerManagerFactoryMockedStatic = - mockStatic(AbstractZkLedgerManagerFactory.class); - LedgerManagerFactory factory = mock(LedgerManagerFactory.class); - abstractZkLedgerManagerFactoryMockedStatic.when(() -> - AbstractZkLedgerManagerFactory.newLedgerManagerFactory(same(conf), same(driver.layoutManager))) - .thenReturn(factory); - - assertSame(factory, driver.getLedgerManagerFactory()); - assertSame(factory, driver.lmFactory); - - AbstractZkLedgerManagerFactory.newLedgerManagerFactory( - same(conf), - same(driver.layoutManager)); - - driver.close(); - verify(factory, times(1)).close(); - assertNull(driver.lmFactory); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java deleted file mode 100644 index e5129fb716e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.meta.zk; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyDouble; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.conf.AbstractConfiguration; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.zookeeper.RetryPolicy; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -/** - * Unit test of {@link ZKMetadataDriverBase}. - */ -public abstract class ZKMetadataDriverTestBase { - - protected AbstractConfiguration conf; - protected String ledgersRootPath; - protected String metadataServiceUri; - protected ZooKeeperClient.Builder mockZkBuilder; - protected ZooKeeperClient mockZkc; - protected MockedStatic zooKeeperClientMockedStatic; - - public void setup(AbstractConfiguration conf) throws Exception { - ledgersRootPath = "/path/to/ledgers"; - metadataServiceUri = "zk://127.0.0.1" + ledgersRootPath; - this.conf = conf; - conf.setMetadataServiceUri(metadataServiceUri); - - this.mockZkBuilder = mock(ZooKeeperClient.Builder.class); - when(mockZkBuilder.connectString(eq("127.0.0.1"))).thenReturn(mockZkBuilder); - when(mockZkBuilder.sessionTimeoutMs(anyInt())).thenReturn(mockZkBuilder); - when(mockZkBuilder.operationRetryPolicy(any(RetryPolicy.class))) - .thenReturn(mockZkBuilder); - when(mockZkBuilder.requestRateLimit(anyDouble())).thenReturn(mockZkBuilder); - when(mockZkBuilder.statsLogger(any(StatsLogger.class))).thenReturn(mockZkBuilder); - - this.mockZkc = mock(ZooKeeperClient.class); - when(mockZkc.exists(anyString(), eq(false))) - .thenReturn(null); - - when(mockZkBuilder.build()).thenReturn(mockZkc); - - zooKeeperClientMockedStatic = Mockito.mockStatic(ZooKeeperClient.class); - zooKeeperClientMockedStatic.when(() -> ZooKeeperClient.newBuilder()).thenReturn(mockZkBuilder); - } - - public void teardown() { - zooKeeperClientMockedStatic.close(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreScannableTableAsyncToSyncConverter.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreScannableTableAsyncToSyncConverter.java deleted file mode 100644 index 72f20a5391b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreScannableTableAsyncToSyncConverter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.metastore; - -import java.util.Set; -import org.apache.bookkeeper.metastore.MetastoreScannableTable.Order; - -/** - * Async to sync converter for a metastore scannable table. - */ -public class MetastoreScannableTableAsyncToSyncConverter extends - MetastoreTableAsyncToSyncConverter { - - private MetastoreScannableTable scannableTable; - - public MetastoreScannableTableAsyncToSyncConverter( - MetastoreScannableTable table) { - super(table); - this.scannableTable = table; - } - - public MetastoreCursor openCursor(String firstKey, boolean firstInclusive, - String lastKey, boolean lastInclusive, - Order order) - throws MSException { - HeldValue retValue = new HeldValue(); - // make the actual async call - this.scannableTable.openCursor(firstKey, firstInclusive, lastKey, lastInclusive, - order, retValue, null); - retValue.waitCallback(); - return retValue.getValue(); - } - - public MetastoreCursor openCursor(String firstKey, boolean firstInclusive, - String lastKey, boolean lastInclusive, - Order order, Set fields) - throws MSException { - HeldValue retValue = new HeldValue(); - // make the actual async call - this.scannableTable.openCursor(firstKey, firstInclusive, lastKey, lastInclusive, - order, fields, retValue, null); - retValue.waitCallback(); - return retValue.getValue(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreTableAsyncToSyncConverter.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreTableAsyncToSyncConverter.java deleted file mode 100644 index aee1b0f83f9..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreTableAsyncToSyncConverter.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.metastore; - -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.metastore.MSException.Code; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; - -/** - * Converts async calls to sync calls for MetastoreTable. Currently not - * intended to be used other than for simple functional tests, however, - * could be developed into a sync API. - */ -public class MetastoreTableAsyncToSyncConverter { - - static class HeldValue implements MetastoreCallback { - private CountDownLatch countDownLatch = new CountDownLatch(1); - private int code; - private T value = null; - - void waitCallback() throws MSException { - try { - countDownLatch.await(10, TimeUnit.SECONDS); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw MSException.create(Code.InterruptedException); - } - - if (Code.OK.getCode() != code) { - throw MSException.create(Code.get(code)); - } - } - - public T getValue() { - return value; - } - - @Override - public void complete(int rc, T value, Object ctx) { - this.code = rc; - this.value = value; - countDownLatch.countDown(); - } - } - - protected MetastoreTable table; - - public MetastoreTableAsyncToSyncConverter(MetastoreTable table) { - this.table = table; - } - - public Versioned get(String key) throws MSException { - HeldValue> retValue = - new HeldValue>(); - - // make the actual async call - this.table.get(key, retValue, null); - - retValue.waitCallback(); - return retValue.getValue(); - } - - public Versioned get(String key, Set fields) - throws MSException { - HeldValue> retValue = - new HeldValue>(); - - // make the actual async call - this.table.get(key, fields, retValue, null); - - retValue.waitCallback(); - return retValue.getValue(); - } - - public void remove(String key, Version version) throws MSException { - HeldValue retValue = new HeldValue(); - - // make the actual async call - this.table.remove(key, version, retValue, null); - - retValue.waitCallback(); - } - - public Version put(String key, Value value, Version version) - throws MSException { - HeldValue retValue = new HeldValue(); - - // make the actual async call - this.table.put(key, value, version, retValue, null); - - retValue.waitCallback(); - return retValue.getValue(); - } - - public MetastoreCursor openCursor() throws MSException { - HeldValue retValue = new HeldValue(); - // make the actual async call - this.table.openCursor(retValue, null); - retValue.waitCallback(); - return retValue.getValue(); - } - - public MetastoreCursor openCursor(Set fields) throws MSException { - HeldValue retValue = new HeldValue(); - // make the actual async call - this.table.openCursor(fields, retValue, null); - retValue.waitCallback(); - return retValue.getValue(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/TestMetaStore.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/TestMetaStore.java deleted file mode 100644 index bd89733cec2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/TestMetaStore.java +++ /dev/null @@ -1,650 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.metastore; - -import static org.apache.bookkeeper.metastore.MetastoreScannableTable.EMPTY_END_KEY; -import static org.apache.bookkeeper.metastore.MetastoreScannableTable.EMPTY_START_KEY; -import static org.apache.bookkeeper.metastore.MetastoreTable.ALL_FIELDS; -import static org.apache.bookkeeper.metastore.MetastoreTable.NON_FIELDS; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.MapDifference; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import org.apache.bookkeeper.metastore.InMemoryMetastoreTable.MetadataVersion; -import org.apache.bookkeeper.metastore.MSException.Code; -import org.apache.bookkeeper.metastore.MetastoreScannableTable.Order; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the metastore. - */ -public class TestMetaStore { - private static final Logger logger = LoggerFactory.getLogger(TestMetaStore.class); - - protected static final String TABLE = "myTable"; - protected static final String RECORDID = "test"; - protected static final String FIELD_NAME = "name"; - protected static final String FIELD_COUNTER = "counter"; - - protected String getFieldFromValue(Value value, String field) { - byte[] v = value.getField(field); - return v == null ? null : new String(v); - } - - protected static Value makeValue(String name, Integer counter) { - Value data = new Value(); - - if (name != null) { - data.setField(FIELD_NAME, name.getBytes()); - } - - if (counter != null) { - data.setField(FIELD_COUNTER, counter.toString().getBytes()); - } - - return data; - } - - /** - * A metastore record. - */ - protected class Record { - String name; - Integer counter; - Version version; - - public Record() { - } - - public Record(String name, Integer counter, Version version) { - this.name = name; - this.counter = counter; - this.version = version; - } - - public Record(Versioned vv) { - version = vv.getVersion(); - - Value value = vv.getValue(); - if (value == null) { - return; - } - - name = getFieldFromValue(value, FIELD_NAME); - String c = getFieldFromValue(value, FIELD_COUNTER); - if (c != null) { - counter = Integer.parseInt(c); - } - } - - public Version getVersion() { - return version; - } - - public Value getValue() { - return TestMetaStore.makeValue(name, counter); - } - - public Versioned getVersionedValue() { - return new Versioned(getValue(), version); - } - - public void merge(String name, Integer counter, Version version) { - if (name != null) { - this.name = name; - } - if (counter != null) { - this.counter = counter; - } - if (version != null) { - this.version = version; - } - } - - public void merge(Record record) { - merge(record.name, record.counter, record.version); - } - - public void checkEqual(Versioned vv) { - Version v = vv.getVersion(); - Value value = vv.getValue(); - - assertEquals(name, getFieldFromValue(value, FIELD_NAME)); - - String c = getFieldFromValue(value, FIELD_COUNTER); - if (counter == null) { - assertNull(c); - } else { - assertEquals(counter.toString(), c); - } - - assertTrue(isEqualVersion(version, v)); - } - - } - - protected MetaStore metastore; - protected MetastoreScannableTable myActualTable; - protected MetastoreScannableTableAsyncToSyncConverter myTable; - - protected String getMetaStoreName() { - return InMemoryMetaStore.class.getName(); - } - - protected Configuration getConfiguration() { - return new CompositeConfiguration(); - } - - protected Version newBadVersion() { - return new MetadataVersion(-1); - } - - protected Version nextVersion(Version version) { - if (Version.NEW == version) { - return new MetadataVersion(0); - } - if (Version.ANY == version) { - return Version.ANY; - } - assertTrue(version instanceof MetadataVersion); - return new MetadataVersion(((MetadataVersion) version).incrementVersion()); - } - - private void checkVersion(Version v) { - assertNotNull(v); - if (v != Version.NEW && v != Version.ANY) { - assertTrue(v instanceof MetadataVersion); - } - } - - protected boolean isEqualVersion(Version v1, Version v2) { - checkVersion(v1); - checkVersion(v2); - return v1.compare(v2) == Version.Occurred.CONCURRENTLY; - } - - @Before - public void setUp() throws Exception { - metastore = MetastoreFactory.createMetaStore(getMetaStoreName()); - Configuration config = getConfiguration(); - metastore.init(config, metastore.getVersion()); - - myActualTable = metastore.createScannableTable(TABLE); - myTable = new MetastoreScannableTableAsyncToSyncConverter(myActualTable); - - // setup a clean environment - clearTable(); - } - - @After - public void tearDown() throws Exception { - // also clear table after test - clearTable(); - - myActualTable.close(); - metastore.close(); - } - - void checkExpectedValue(Versioned vv, String expectedName, - Integer expectedCounter, Version expectedVersion) { - Record expected = new Record(expectedName, expectedCounter, expectedVersion); - expected.checkEqual(vv); - } - - protected Integer getRandom() { - return (int) (Math.random() * 65536); - } - - protected Versioned getRecord(String recordId) throws Exception { - try { - return myTable.get(recordId); - } catch (MSException.NoKeyException nke) { - return null; - } - } - - /** - * get record with specific fields, assume record EXIST! - */ - protected Versioned getExistRecordFields(String recordId, Set fields) - throws Exception { - Versioned retValue = myTable.get(recordId, fields); - return retValue; - } - - /** - * put and check fields. - */ - protected void putAndCheck(String recordId, String name, - Integer counter, Version version, - Record expected, Code expectedCode) - throws Exception { - Version retVersion = null; - Code code = Code.OperationFailure; - try { - retVersion = myTable.put(recordId, makeValue(name, counter), version); - code = Code.OK; - } catch (MSException.BadVersionException bve) { - code = Code.BadVersion; - } catch (MSException.NoKeyException nke) { - code = Code.NoKey; - } catch (MSException.KeyExistsException kee) { - code = Code.KeyExists; - } - assertEquals(expectedCode, code); - - // get and check all fields of record - if (Code.OK == code) { - assertTrue(isEqualVersion(retVersion, nextVersion(version))); - expected.merge(name, counter, retVersion); - } - - Versioned existedVV = getRecord(recordId); - if (null == expected) { - assertNull(existedVV); - } else { - expected.checkEqual(existedVV); - } - } - - protected void clearTable() throws Exception { - MetastoreCursor cursor = myTable.openCursor(); - if (!cursor.hasMoreEntries()) { - return; - } - while (cursor.hasMoreEntries()) { - Iterator iter = cursor.readEntries(99); - while (iter.hasNext()) { - MetastoreTableItem item = iter.next(); - String key = item.getKey(); - myTable.remove(key, Version.ANY); - } - } - cursor.close(); - } - - /** - * Test (get, get partial field, remove) on non-existent element. - */ - @Test - public void testNonExistent() throws Exception { - // get - try { - myTable.get(RECORDID); - fail("Should fail to get a non-existent key"); - } catch (MSException.NoKeyException nke) { - } - - // get partial field - Set fields = - new HashSet(Collections.singletonList(FIELD_COUNTER)); - try { - myTable.get(RECORDID, fields); - fail("Should fail to get a non-existent key with specified fields"); - } catch (MSException.NoKeyException nke) { - } - - // remove - try { - myTable.remove(RECORDID, Version.ANY); - fail("Should fail to delete a non-existent key"); - } catch (MSException.NoKeyException nke) { - } - } - - /** - * Test usage of get operation on (full and partial) fields. - */ - @Test - public void testGet() throws Exception { - Versioned vv; - - final Set fields = - new HashSet(Collections.singletonList(FIELD_NAME)); - - final String name = "get"; - final Integer counter = getRandom(); - - // put test item - Version version = myTable.put(RECORDID, makeValue(name, counter), Version.NEW); - assertNotNull(version); - - // fetch with all fields - vv = getExistRecordFields(RECORDID, ALL_FIELDS); - checkExpectedValue(vv, name, counter, version); - - // partial get name - vv = getExistRecordFields(RECORDID, fields); - checkExpectedValue(vv, name, null, version); - - // non fields - vv = getExistRecordFields(RECORDID, NON_FIELDS); - checkExpectedValue(vv, null, null, version); - - // get null key should fail - try { - getExistRecordFields(null, NON_FIELDS); - fail("Should fail to get null key with NON fields"); - } catch (MSException.IllegalOpException ioe) { - } - try { - getExistRecordFields(null, ALL_FIELDS); - fail("Should fail to get null key with ALL fields."); - } catch (MSException.IllegalOpException ioe) { - } - try { - getExistRecordFields(null, fields); - fail("Should fail to get null key with fields " + fields); - } catch (MSException.IllegalOpException ioe) { - } - } - - /** - * Test usage of put operation with (full and partial) fields. - */ - @Test - public void testPut() throws Exception { - final Integer counter = getRandom(); - final String name = "put"; - - Version version; - - /** - * test correct version put - */ - // put test item - version = myTable.put(RECORDID, makeValue(name, counter), Version.NEW); - assertNotNull(version); - Record expected = new Record(name, counter, version); - - // correct version put with only name field changed - putAndCheck(RECORDID, "name1", null, expected.getVersion(), expected, Code.OK); - - // correct version put with only counter field changed - putAndCheck(RECORDID, null, counter + 1, expected.getVersion(), expected, Code.OK); - - // correct version put with all fields filled - putAndCheck(RECORDID, "name2", counter + 2, expected.getVersion(), expected, Code.OK); - - // test put exist entry with Version.ANY - checkPartialPut("put exist entry with Version.ANY", Version.ANY, expected, Code.OK); - - /** - * test bad version put - */ - // put to existed entry with Version.NEW - badVersionedPut(Version.NEW, Code.KeyExists); - // put to existed entry with bad version - badVersionedPut(newBadVersion(), Code.BadVersion); - - // remove the entry - myTable.remove(RECORDID, Version.ANY); - - // put to non-existent entry with bad version - badVersionedPut(newBadVersion(), Code.NoKey); - // put to non-existent entry with Version.ANY - badVersionedPut(Version.ANY, Code.NoKey); - - /** - * test illegal arguments - */ - illegalPut(null, Version.NEW); - illegalPut(makeValue("illegal value", getRandom()), null); - illegalPut(null, null); - } - - protected void badVersionedPut(Version badVersion, Code expectedCode) throws Exception { - Versioned vv = getRecord(RECORDID); - Record expected = null; - - if (expectedCode != Code.NoKey) { - assertNotNull(vv); - expected = new Record(vv); - } - - checkPartialPut("badVersionedPut", badVersion, expected, expectedCode); - } - - protected void checkPartialPut(String name, Version version, Record expected, Code expectedCode) - throws Exception { - Integer counter; - - // bad version put with all fields filled - counter = getRandom(); - putAndCheck(RECORDID, name + counter, counter, version, expected, expectedCode); - - // bad version put with only name field changed - counter = getRandom(); - putAndCheck(RECORDID, name + counter, null, version, expected, expectedCode); - - // bad version put with only counter field changed - putAndCheck(RECORDID, null, counter, version, expected, expectedCode); - } - - protected void illegalPut(Value value, Version version) throws MSException { - try { - myTable.put(RECORDID, value, version); - fail("Should fail to do versioned put with illegal arguments"); - } catch (MSException.IllegalOpException ioe) { - } - } - - /** - * Test usage of (unconditional remove, BadVersion remove, CorrectVersion - * remove) operation. - */ - @Test - public void testRemove() throws Exception { - final Integer counter = getRandom(); - final String name = "remove"; - Version version; - - // insert test item - version = myTable.put(RECORDID, makeValue(name, counter), Version.NEW); - assertNotNull(version); - - // test unconditional remove - myTable.remove(RECORDID, Version.ANY); - - // insert test item - version = myTable.put(RECORDID, makeValue(name, counter), Version.NEW); - assertNotNull(version); - - // test remove with bad version - try { - myTable.remove(RECORDID, Version.NEW); - fail("Should fail to remove a given key with bad version"); - } catch (MSException.BadVersionException bve) { - } - try { - myTable.remove(RECORDID, newBadVersion()); - fail("Should fail to remove a given key with bad version"); - } catch (MSException.BadVersionException bve) { - } - - // test remove with correct version - myTable.remove(RECORDID, version); - } - - protected void openCursorTest(MetastoreCursor cursor, Map expectedValues, - int numEntriesPerScan) throws Exception { - try { - Map entries = Maps.newHashMap(); - while (cursor.hasMoreEntries()) { - Iterator iter = cursor.readEntries(numEntriesPerScan); - while (iter.hasNext()) { - MetastoreTableItem item = iter.next(); - entries.put(item.getKey(), item.getValue().getValue()); - } - } - MapDifference diff = Maps.difference(expectedValues, entries); - assertTrue(diff.areEqual()); - } finally { - cursor.close(); - } - } - - void openRangeCursorTest(String firstKey, boolean firstInclusive, - String lastKey, boolean lastInclusive, - Order order, Set fields, - Iterator> expectedValues, - int numEntriesPerScan) throws Exception { - try (MetastoreCursor cursor = - myTable.openCursor(firstKey, firstInclusive, lastKey, lastInclusive, order, fields)) { - while (cursor.hasMoreEntries()) { - Iterator iter = cursor.readEntries(numEntriesPerScan); - while (iter.hasNext()) { - assertTrue(expectedValues.hasNext()); - MetastoreTableItem item = iter.next(); - Map.Entry expectedItem = expectedValues.next(); - assertEquals(expectedItem.getKey(), item.getKey()); - assertEquals(expectedItem.getValue(), item.getValue().getValue()); - } - } - assertFalse(expectedValues.hasNext()); - } - } - - /** - * Test usage of (scan) operation on (full and partial) fields. - */ - @Test - public void testOpenCursor() throws Exception { - - TreeMap allValues = Maps.newTreeMap(); - TreeMap partialValues = Maps.newTreeMap(); - TreeMap nonValues = Maps.newTreeMap(); - - Set counterFields = Sets.newHashSet(FIELD_COUNTER); - - for (int i = 5; i < 24; i++) { - char c = (char) ('a' + i); - String key = String.valueOf(c); - Value v = makeValue("value" + i, i); - Value cv = v.project(counterFields); - Value nv = v.project(NON_FIELDS); - - myTable.put(key, new Value(v), Version.NEW); - allValues.put(key, v); - partialValues.put(key, cv); - nonValues.put(key, nv); - } - - // test open cursor - MetastoreCursor cursor = myTable.openCursor(ALL_FIELDS); - openCursorTest(cursor, allValues, 7); - - cursor = myTable.openCursor(counterFields); - openCursorTest(cursor, partialValues, 7); - - cursor = myTable.openCursor(NON_FIELDS); - openCursorTest(cursor, nonValues, 7); - - // test order inclusive exclusive - Iterator> expectedIterator; - - expectedIterator = allValues.subMap("l", true, "u", true).entrySet().iterator(); - openRangeCursorTest("l", true, "u", true, Order.ASC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.descendingMap().subMap("u", true, "l", true) - .entrySet().iterator(); - openRangeCursorTest("u", true, "l", true, Order.DESC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.subMap("l", false, "u", false).entrySet().iterator(); - openRangeCursorTest("l", false, "u", false, Order.ASC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.descendingMap().subMap("u", false, "l", false) - .entrySet().iterator(); - openRangeCursorTest("u", false, "l", false, Order.DESC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.subMap("l", true, "u", false).entrySet().iterator(); - openRangeCursorTest("l", true, "u", false, Order.ASC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.descendingMap().subMap("u", true, "l", false) - .entrySet().iterator(); - openRangeCursorTest("u", true, "l", false, Order.DESC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.subMap("l", false, "u", true).entrySet().iterator(); - openRangeCursorTest("l", false, "u", true, Order.ASC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.descendingMap().subMap("u", false, "l", true) - .entrySet().iterator(); - openRangeCursorTest("u", false, "l", true, Order.DESC, ALL_FIELDS, expectedIterator, 7); - - // test out of range - String firstKey = "f"; - String lastKey = "x"; - expectedIterator = allValues.subMap(firstKey, true, lastKey, true) - .entrySet().iterator(); - openRangeCursorTest("a", true, "z", true, Order.ASC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.subMap("l", true, lastKey, true).entrySet().iterator(); - openRangeCursorTest("l", true, "z", true, Order.ASC, ALL_FIELDS, expectedIterator, 7); - - expectedIterator = allValues.subMap(firstKey, true, "u", true).entrySet().iterator(); - openRangeCursorTest("a", true, "u", true, Order.ASC, ALL_FIELDS, expectedIterator, 7); - - // test EMPTY_START_KEY and EMPTY_END_KEY - expectedIterator = allValues.subMap(firstKey, true, "u", true).entrySet().iterator(); - openRangeCursorTest(EMPTY_START_KEY, true, "u", true, Order.ASC, ALL_FIELDS, - expectedIterator, 7); - - expectedIterator = allValues.descendingMap().subMap(lastKey, true, "l", true) - .entrySet().iterator(); - openRangeCursorTest(EMPTY_END_KEY, true, "l", true, Order.DESC, ALL_FIELDS, - expectedIterator, 7); - - // test illegal arguments - try { - myTable.openCursor("a", true, "z", true, Order.DESC, ALL_FIELDS); - fail("Should fail with wrong range"); - } catch (MSException.IllegalOpException ioe) { - } - try { - myTable.openCursor("z", true, "a", true, Order.ASC, ALL_FIELDS); - fail("Should fail with wrong range"); - } catch (MSException.IllegalOpException ioe) { - } - try { - myTable.openCursor("a", true, "z", true, null, ALL_FIELDS); - fail("Should fail with null order"); - } catch (MSException.IllegalOpException ioe) { - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/BookieIdTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/BookieIdTest.java deleted file mode 100644 index d32378b5001..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/BookieIdTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.net; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import java.util.UUID; -import org.junit.Test; - -/** - * Unit tests for BookieId class. - */ -public class BookieIdTest { - - @Test - public void testToString() { - assertEquals("test", BookieId.parse("test").toString()); - } - - @Test - public void testParse() { - assertEquals("test", BookieId.parse("test").getId()); - } - - @Test - public void testEquals() { - assertEquals(BookieId.parse("test"), BookieId.parse("test")); - assertNotEquals(BookieId.parse("test"), BookieId.parse("test2")); - } - - @Test - public void testHashcode() { - assertEquals(BookieId.parse("test").hashCode(), BookieId.parse("test").hashCode()); - } - - @Test(expected = IllegalArgumentException.class) - public void testValidate1() { - BookieId.parse("non valid"); - } - - @Test(expected = IllegalArgumentException.class) - public void testValidate2() { - BookieId.parse("non$valid"); - } - - @Test(expected = IllegalArgumentException.class) - public void testValidateReservedWord() { - // 'readonly' is a reserved word for the ZK based implementation - BookieId.parse("readonly"); - } - - @Test - public void testValidateHostnamePort() { - BookieId.parse("this.is.an.hostname:1234"); - } - - @Test - public void testValidateIPv4Port() { - BookieId.parse("1.2.3.4:1234"); - } - - @Test - public void testValidateUUID() { - BookieId.parse(UUID.randomUUID().toString()); - } - - @Test - public void testWithDashAndUnderscore() { - BookieId.parse("testRegisterUnregister_ReadonlyBookie-readonly:3181"); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/NetworkTopologyImplTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/NetworkTopologyImplTest.java deleted file mode 100644 index e9ed1577e75..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/NetworkTopologyImplTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.net; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Set; -import org.junit.Test; - -/** - * Tests for {@link NetworkTopologyImpl}. - */ -public class NetworkTopologyImplTest { - - @Test - public void getLeavesShouldReturnEmptySetForNonExistingScope() { - NetworkTopologyImpl networkTopology = new NetworkTopologyImpl(); - final Set leaves = networkTopology.getLeaves("/non-existing-scope"); - assertTrue(leaves.isEmpty()); - } - - @Test - public void getLeavesShouldReturnNodesInScope() { - // GIVEN - // Topology with two racks and 1 bookie in each rack. - NetworkTopologyImpl networkTopology = new NetworkTopologyImpl(); - - String rack0Scope = "/rack-0"; - BookieId bookieIdScopeRack0 = BookieId.parse("bookieIdScopeRack0"); - BookieNode bookieRack0ScopeNode = new BookieNode(bookieIdScopeRack0, rack0Scope); - - String rack1Scope = "/rack-1"; - BookieId bookieIdScopeRack1 = BookieId.parse("bookieIdScopeRack1"); - BookieNode bookieRack1ScopeNode = new BookieNode(bookieIdScopeRack1, rack1Scope); - - networkTopology.add(bookieRack0ScopeNode); - networkTopology.add(bookieRack1ScopeNode); - - // WHEN - Set leavesScopeRack0 = networkTopology.getLeaves(rack0Scope); - Set leavesScopeRack1 = networkTopology.getLeaves(rack1Scope); - - // THEN - assertTrue(leavesScopeRack0.size() == 1); - assertTrue(leavesScopeRack0.contains(bookieRack0ScopeNode)); - - assertTrue(leavesScopeRack1.size() == 1); - assertTrue(leavesScopeRack1.contains(bookieRack1ScopeNode)); - } - - @Test - public void testRestartBKWithNewRackDepth() { - NetworkTopologyImpl networkTopology = new NetworkTopologyImpl(); - String dp1Rack = "/rack-1"; - String dp2Rack = "/dp/rack-1"; - BookieId bkId1 = BookieId.parse("bookieIdScopeRack0"); - BookieId bkId2 = BookieId.parse("bookieIdScopeRack1"); - - // Register 2 BKs with depth 1 rack. - BookieNode dp1BkNode1 = new BookieNode(bkId1, dp1Rack); - BookieNode dp1BkNode2 = new BookieNode(bkId2, dp1Rack); - networkTopology.add(dp1BkNode1); - networkTopology.add(dp1BkNode2); - - // Update one BK with depth 2 rack. - // Assert it can not be added due to different depth. - networkTopology.remove(dp1BkNode1); - BookieNode dp2BkNode1 = new BookieNode(bkId1, dp2Rack); - try { - networkTopology.add(dp2BkNode1); - fail("Expected add node failed caused by different depth of rack"); - } catch (NetworkTopologyImpl.InvalidTopologyException ex) { - // Expected ex. - } - Set leaves = networkTopology.getLeaves(dp1Rack); - assertEquals(leaves.size(), 1); - assertTrue(leaves.contains(dp1BkNode2)); - - // Update all Bks with depth 2 rack. - // Verify update success. - networkTopology.remove(dp1BkNode2); - BookieNode dp2BkNode2 = new BookieNode(bkId2, dp2Rack); - networkTopology.add(dp2BkNode1); - networkTopology.add(dp2BkNode2); - leaves = networkTopology.getLeaves(dp2Rack); - assertEquals(leaves.size(), 2); - assertTrue(leaves.contains(dp2BkNode1)); - assertTrue(leaves.contains(dp2BkNode2)); - } - - @Test - public void getLeavesShouldReturnLeavesThatAreNotInExcludedScope() { - // GIVEN - // Topology with three racks and 1 bookie in each rack. - NetworkTopologyImpl networkTopology = new NetworkTopologyImpl(); - - String rack0Scope = "/rack-0"; - BookieId bookieIdScopeRack0 = BookieId.parse("bookieIdScopeRack0"); - BookieNode bookieRack0ScopeNode = new BookieNode(bookieIdScopeRack0, rack0Scope); - - String rack1Scope = "/rack-1"; - BookieId bookieIdScopeRack1 = BookieId.parse("bookieIdScopeRack1"); - BookieNode bookieRack1ScopeNode = new BookieNode(bookieIdScopeRack1, rack1Scope); - - String rack2Scope = "/rack-2"; - BookieId bookieIdScopeRack2 = BookieId.parse("bookieIdScopeRack2"); - BookieNode bookieRack2ScopeNode = new BookieNode(bookieIdScopeRack2, rack2Scope); - - networkTopology.add(bookieRack0ScopeNode); - networkTopology.add(bookieRack1ScopeNode); - networkTopology.add(bookieRack2ScopeNode); - - // Excluded scopes are beginned with '~' character. - String scopeExcludingRack1 = "~/rack-1"; - - // WHEN - // ask for leaves not being at rack1 scope. - Set leavesExcludingRack2Scope = networkTopology.getLeaves(scopeExcludingRack1); - - // THEN - assertTrue(leavesExcludingRack2Scope.size() == 2); - assertTrue(leavesExcludingRack2Scope.contains(bookieRack0ScopeNode)); - assertTrue(leavesExcludingRack2Scope.contains(bookieRack2ScopeNode)); - } - - @Test - public void testInvalidRackName() { - NetworkTopologyImpl networkTopology = new NetworkTopologyImpl(); - String rack0Scope = ""; - BookieId bookieIdScopeRack0 = BookieId.parse("bookieIdScopeRack0"); - BookieNode bookieRack0ScopeNode = new BookieNode(bookieIdScopeRack0, rack0Scope); - - String rack1Scope = "/"; - BookieId bookieIdScopeRack1 = BookieId.parse("bookieIdScopeRack1"); - BookieNode bookieRack1ScopeNode = new BookieNode(bookieIdScopeRack1, rack1Scope); - - try { - networkTopology.add(bookieRack0ScopeNode); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("bookieIdScopeRack0, which is located at , is not a decendent of /", e.getMessage()); - } - - try { - networkTopology.add(bookieRack1ScopeNode); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("bookieIdScopeRack1, which is located at , is not a decendent of /", e.getMessage()); - } - - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/ResolvedBookieSocketAddressTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/ResolvedBookieSocketAddressTest.java deleted file mode 100644 index 62d59b5999e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/net/ResolvedBookieSocketAddressTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.net; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.net.InetSocketAddress; -import org.junit.Test; - -/** - * Tests for BookieSocketAddress getSocketAddress cache logic. - */ - -public class ResolvedBookieSocketAddressTest { - - @Test - public void testHostnameBookieId() throws Exception { - BookieSocketAddress hostnameAddress = new BookieSocketAddress("localhost", 3181); - InetSocketAddress inetSocketAddress1 = hostnameAddress.getSocketAddress(); - InetSocketAddress inetSocketAddress2 = hostnameAddress.getSocketAddress(); - assertFalse("InetSocketAddress should be recreated", inetSocketAddress1 == inetSocketAddress2); - } - - @Test - public void testIPAddressBookieId() throws Exception { - BookieSocketAddress ipAddress = new BookieSocketAddress("127.0.0.1", 3181); - InetSocketAddress inetSocketAddress1 = ipAddress.getSocketAddress(); - InetSocketAddress inetSocketAddress2 = ipAddress.getSocketAddress(); - assertTrue("InetSocketAddress should be cached", inetSocketAddress1 == inetSocketAddress2); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BatchedReadEntryProcessorTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BatchedReadEntryProcessorTest.java deleted file mode 100644 index 3f897558384..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BatchedReadEntryProcessorTest.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.channel.DefaultChannelPromise; -import io.netty.channel.EventLoop; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.proto.BookieProtocol.Response; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Before; -import org.junit.Test; - - - -/** - * Unit test {@link ReadEntryProcessor}. - */ -public class BatchedReadEntryProcessorTest { - - private Channel channel; - private BookieRequestHandler requestHandler; - private BookieRequestProcessor requestProcessor; - private Bookie bookie; - - @Before - public void setup() throws IOException, BookieException { - channel = mock(Channel.class); - when(channel.isOpen()).thenReturn(true); - - requestHandler = mock(BookieRequestHandler.class); - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - when(requestHandler.ctx()).thenReturn(ctx); - - bookie = mock(Bookie.class); - requestProcessor = mock(BookieRequestProcessor.class); - when(requestProcessor.getBookie()).thenReturn(bookie); - when(requestProcessor.getWaitTimeoutOnBackpressureMillis()).thenReturn(-1L); - when(requestProcessor.getRequestStats()).thenReturn(new RequestStats(NullStatsLogger.INSTANCE)); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - when(channel.writeAndFlush(any())).thenReturn(mock(ChannelPromise.class)); - EventLoop eventLoop = mock(EventLoop.class); - when(eventLoop.inEventLoop()).thenReturn(true); - when(channel.eventLoop()).thenReturn(eventLoop); - ByteBuf buffer0 = ByteBufAllocator.DEFAULT.buffer(4); - ByteBuf buffer1 = ByteBufAllocator.DEFAULT.buffer(4); - ByteBuf buffer2 = ByteBufAllocator.DEFAULT.buffer(4); - ByteBuf buffer3 = ByteBufAllocator.DEFAULT.buffer(4); - ByteBuf buffer4 = ByteBufAllocator.DEFAULT.buffer(4); - - when(bookie.readEntry(anyLong(), anyLong())).thenReturn(buffer0).thenReturn(buffer1).thenReturn(buffer2) - .thenReturn(buffer3).thenReturn(buffer4); - } - - @Test - public void testSuccessfulAsynchronousFenceRequest() throws Exception { - testAsynchronousRequest(true, BookieProtocol.EOK); - } - - @Test - public void testFailedAsynchronousFenceRequest() throws Exception { - testAsynchronousRequest(false, BookieProtocol.EIO); - } - - private void testAsynchronousRequest(boolean result, int errorCode) throws Exception { - CompletableFuture fenceResult = FutureUtils.createFuture(); - when(bookie.fenceLedger(anyLong(), any())).thenReturn(fenceResult); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - promise.setSuccess(); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any(Response.class)); - - long requestId = 0; - int maxCount = 5; - long maxSize = 1024; - ExecutorService service = Executors.newCachedThreadPool(); - long ledgerId = System.currentTimeMillis(); - BookieProtocol.BatchedReadRequest request = BookieProtocol.BatchedReadRequest.create( - BookieProtocol.CURRENT_PROTOCOL_VERSION, ledgerId, 1, BookieProtocol.FLAG_DO_FENCING, new byte[] {}, - requestId, maxCount, maxSize); - ReadEntryProcessor processor = BatchedReadEntryProcessor.create( - request, requestHandler, requestProcessor, service, true, 1024 * 1024 * 5); - processor.run(); - - fenceResult.complete(result); - latch.await(); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(1, response.getEntryId()); - assertEquals(ledgerId, response.getLedgerId()); - assertEquals(BookieProtocol.BATCH_READ_ENTRY, response.getOpCode()); - assertEquals(errorCode, response.getErrorCode()); - service.shutdown(); - } - - @Test - public void testSuccessfulSynchronousFenceRequest() throws Exception { - testSynchronousRequest(true, BookieProtocol.EOK); - } - - @Test - public void testFailedSynchronousFenceRequest() throws Exception { - testSynchronousRequest(false, BookieProtocol.EIO); - } - - private void testSynchronousRequest(boolean result, int errorCode) throws Exception { - CompletableFuture fenceResult = FutureUtils.createFuture(); - when(bookie.fenceLedger(anyLong(), any())).thenReturn(fenceResult); - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - promise.setSuccess(); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any(Response.class)); - - long requestId = 0; - int maxCount = 5; - long maxSize = 1024; - ExecutorService service = Executors.newCachedThreadPool(); - long ledgerId = System.currentTimeMillis(); - BookieProtocol.BatchedReadRequest request = BookieProtocol.BatchedReadRequest.create( - BookieProtocol.CURRENT_PROTOCOL_VERSION, ledgerId, 1, BookieProtocol.FLAG_DO_FENCING, new byte[] {}, - requestId, maxCount, maxSize); - ReadEntryProcessor processor = BatchedReadEntryProcessor.create( - request, requestHandler, requestProcessor, service, true, 1024 * 1024 * 5); - fenceResult.complete(result); - processor.run(); - - latch.await(); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(1, response.getEntryId()); - assertEquals(ledgerId, response.getLedgerId()); - assertEquals(BookieProtocol.BATCH_READ_ENTRY, response.getOpCode()); - assertEquals(errorCode, response.getErrorCode()); - } - - @Test - public void testNonFenceRequest() throws Exception { - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - promise.setSuccess(); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any(Response.class)); - - long requestId = 0; - int maxCount = 5; - long maxSize = 1024; - ExecutorService service = Executors.newCachedThreadPool(); - long ledgerId = System.currentTimeMillis(); - BookieProtocol.BatchedReadRequest request = BookieProtocol.BatchedReadRequest.create( - BookieProtocol.CURRENT_PROTOCOL_VERSION, ledgerId, 1, BookieProtocol.FLAG_DO_FENCING, new byte[] {}, - requestId, maxCount, maxSize); - ReadEntryProcessor processor = BatchedReadEntryProcessor.create( - request, requestHandler, requestProcessor, service, true, 1024 * 1024 * 5); - processor.run(); - - latch.await(); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(1, response.getEntryId()); - assertEquals(ledgerId, response.getLedgerId()); - assertEquals(BookieProtocol.BATCH_READ_ENTRY, response.getOpCode()); - assertEquals(BookieProtocol.EOK, response.getErrorCode()); - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureForV2Test.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureForV2Test.java deleted file mode 100644 index 8721a2c7819..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureForV2Test.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Before; - -/** - * Tests for bckpressure handling on the server side with V2 protocol. - */ -public class BookieBackpressureForV2Test extends BookieBackpressureTest { - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - baseClientConf.setUseV2WireProtocol(true); - bkc = new BookKeeperTestClient(baseClientConf, new TestStatsProvider()); - - // the backpressure will bloc the read response, disable it to let it use backpressure mechanism - confByIndex(0).setReadWorkerThreadsThrottlingEnabled(false); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureTest.java deleted file mode 100644 index 04f4024bf21..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureTest.java +++ /dev/null @@ -1,473 +0,0 @@ -package org.apache.bookkeeper.proto; - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import io.netty.buffer.UnpooledByteBufAllocator; -import java.lang.reflect.Field; -import java.nio.channels.FileChannel; -import java.util.Enumeration; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.Journal; -import org.apache.bookkeeper.bookie.SlowBufferedChannel; -import org.apache.bookkeeper.bookie.SlowInterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.SlowSortedLedgerStorage; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadLastConfirmedCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Tests for backpressure handling on the server side. - */ -// PowerMock usage is problematic here due to https://github.com/powermock/powermock/issues/822 -public class BookieBackpressureTest extends BookKeeperClusterTestCase - implements AddCallback, ReadCallback, ReadLastConfirmedCallback { - - private static final Logger LOG = LoggerFactory.getLogger(BookieBackpressureTest.class); - - byte[] ledgerPassword = "aaa".getBytes(); - - final byte[] data = new byte[8 * 1024]; - - // test related constants - static final int NUM_ENTRIES_TO_WRITE = 200; - static final int ENTRIES_IN_MEMTABLE = 2; - static final int MAX_PENDING = 2 * ENTRIES_IN_MEMTABLE + 1; - static final int NUM_OF_LEDGERS = 2 * MAX_PENDING; - - DigestType digestType; - - long getDelay; - long addDelay; - long flushDelay; - - public BookieBackpressureTest() { - super(1); - this.digestType = DigestType.CRC32; - - baseClientConf.setAddEntryTimeout(100); - baseClientConf.setAddEntryQuorumTimeout(100); - baseClientConf.setReadEntryTimeout(100); - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - getDelay = 0; - addDelay = 0; - flushDelay = 0; - } - - class SyncObj { - long lastConfirmed; - volatile int counter; - boolean value; - AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - Enumeration ls = null; - - public SyncObj() { - counter = 0; - lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - value = false; - } - - void setReturnCode(int rc) { - this.rc.compareAndSet(BKException.Code.OK, rc); - } - - void setLedgerEntries(Enumeration ls) { - this.ls = ls; - } - } - - private Bookie bookieWithMockedJournal(ServerConfiguration conf, - long getDelay, long addDelay, long flushDelay) throws Exception { - Bookie bookie = new TestBookieImpl(conf); - if (getDelay <= 0 && addDelay <= 0 && flushDelay <= 0) { - return bookie; - } - - List journals = getJournals(bookie); - for (int i = 0; i < journals.size(); i++) { - Journal mock = spy(journals.get(i)); - when(mock.getBufferedChannelBuilder()).thenReturn((FileChannel fc, int capacity) -> { - SlowBufferedChannel sbc = new SlowBufferedChannel(UnpooledByteBufAllocator.DEFAULT, fc, capacity); - sbc.setAddDelay(addDelay); - sbc.setGetDelay(getDelay); - sbc.setFlushDelay(flushDelay); - return sbc; - }); - - journals.set(i, mock); - } - return bookie; - } - - @SuppressWarnings("unchecked") - private List getJournals(Bookie bookie) throws NoSuchFieldException, IllegalAccessException { - Field f = BookieImpl.class.getDeclaredField("journals"); - f.setAccessible(true); - - return (List) f.get(bookie); - } - - @Test - public void testWriteNoBackpressureSlowJournal() throws Exception { - //disable backpressure for writes - confByIndex(0).setMaxAddsInProgressLimit(0); - addDelay = 1; - - doWritesNoBackpressure(0); - } - - @Test - public void testWriteNoBackpressureSlowJournalFlush() throws Exception { - //disable backpressure for writes - confByIndex(0).setMaxAddsInProgressLimit(0); - // to increase frequency of flushes - confByIndex(0).setJournalAdaptiveGroupWrites(false); - flushDelay = 1; - - doWritesNoBackpressure(0); - } - - @Test - public void testWriteWithBackpressureSlowJournal() throws Exception { - //enable backpressure with MAX_PENDING writes in progress - confByIndex(0).setMaxAddsInProgressLimit(MAX_PENDING); - flushDelay = 1; - - doWritesWithBackpressure(0); - } - - - @Test - public void testWriteWithBackpressureSlowJournalFlush() throws Exception { - //enable backpressure with MAX_PENDING writes in progress - confByIndex(0).setMaxAddsInProgressLimit(MAX_PENDING); - // to increase frequency of flushes - confByIndex(0).setJournalAdaptiveGroupWrites(false); - flushDelay = 1; - - doWritesWithBackpressure(0); - } - - @Test - public void testWriteNoBackpressureSlowInterleavedStorage() throws Exception { - //disable backpressure for writes - confByIndex(0).setMaxAddsInProgressLimit(0); - confByIndex(0).setLedgerStorageClass(SlowInterleavedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_ADD_DELAY, "1"); - - doWritesNoBackpressure(0); - } - - @Test - public void testWriteWithBackpressureSlowInterleavedStorage() throws Exception { - //enable backpressure with MAX_PENDING writes in progress - confByIndex(0).setMaxAddsInProgressLimit(MAX_PENDING); - confByIndex(0).setLedgerStorageClass(SlowInterleavedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_ADD_DELAY, "1"); - - doWritesWithBackpressure(0); - } - - @Test - public void testWriteNoBackpressureSlowInterleavedStorageFlush() throws Exception { - //disable backpressure for writes - confByIndex(0).setMaxAddsInProgressLimit(0); - confByIndex(0).setLedgerStorageClass(SlowInterleavedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_FLUSH_DELAY, "10"); - - doWritesNoBackpressure(0); - } - - @Test - public void testWriteWithBackpressureSlowInterleavedStorageFlush() throws Exception { - //enable backpressure with MAX_PENDING writes in progress - confByIndex(0).setMaxAddsInProgressLimit(MAX_PENDING); - confByIndex(0).setLedgerStorageClass(SlowInterleavedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_FLUSH_DELAY, "10"); - - doWritesWithBackpressure(0); - } - - @Test - public void testWriteNoBackpressureSortedStorage() throws Exception { - //disable backpressure for writes - confByIndex(0).setMaxAddsInProgressLimit(0); - confByIndex(0).setLedgerStorageClass(SlowSortedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - // one for memtable being flushed, one for the part accepting the data - assertTrue("for the test, memtable should not keep more entries than allowed", - ENTRIES_IN_MEMTABLE * 2 <= MAX_PENDING); - confByIndex(0).setSkipListSizeLimit(data.length * ENTRIES_IN_MEMTABLE - 1); - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_ADD_DELAY, "1"); - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_FLUSH_DELAY, "10"); - - doWritesNoBackpressure(0); - } - - @Test - public void testWriteWithBackpressureSortedStorage() throws Exception { - //enable backpressure with MAX_PENDING writes in progress - confByIndex(0).setMaxAddsInProgressLimit(MAX_PENDING); - confByIndex(0).setLedgerStorageClass(SlowSortedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - // one for memtable being flushed, one for the part accepting the data - assertTrue("for the test, memtable should not keep more entries than allowed", - ENTRIES_IN_MEMTABLE * 2 <= MAX_PENDING); - confByIndex(0).setSkipListSizeLimit(data.length * ENTRIES_IN_MEMTABLE - 1); - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_ADD_DELAY, "1"); - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_FLUSH_DELAY, "10"); - - doWritesWithBackpressure(0); - } - - @Test - public void testReadsNoBackpressure() throws Exception { - //disable backpressure for reads - confByIndex(0).setMaxReadsInProgressLimit(0); - confByIndex(0).setLedgerStorageClass(SlowInterleavedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_GET_DELAY, "1"); - - final BookieRequestProcessor brp = generateDataAndDoReads(0); - - Assert.assertThat("reads in progress should exceed MAX_PENDING", - brp.maxReadsInProgressCount(), Matchers.greaterThan(MAX_PENDING)); - } - - @Test - public void testReadsWithBackpressure() throws Exception { - //enable backpressure for reads - confByIndex(0).setMaxReadsInProgressLimit(MAX_PENDING); - confByIndex(0).setLedgerStorageClass(SlowInterleavedLedgerStorage.class.getName()); - confByIndex(0).setWriteBufferBytes(data.length); - - confByIndex(0).setProperty(SlowInterleavedLedgerStorage.PROP_SLOW_STORAGE_GET_DELAY, "1"); - - final BookieRequestProcessor brp = generateDataAndDoReads(0); - - Assert.assertThat("reads in progress should NOT exceed MAX_PENDING ", - brp.maxReadsInProgressCount(), Matchers.lessThanOrEqualTo(MAX_PENDING)); - } - - private BookieRequestProcessor generateDataAndDoReads(final int bkId) throws Exception { - Assert.assertThat("should be only one bookie", - bookieCount(), Matchers.equalTo(1)); - ServerConfiguration conf = killBookie(0); - BookieServer bks = startAndAddBookie(conf, - bookieWithMockedJournal(conf, getDelay, addDelay, flushDelay)) - .getServer(); - - LOG.info("creating ledgers"); - // Create ledgers - final int numEntriesForReads = 10; - LedgerHandle[] lhs = new LedgerHandle[NUM_OF_LEDGERS]; - for (int i = 0; i < NUM_OF_LEDGERS; i++) { - lhs[i] = bkc.createLedger(1, 1, digestType, ledgerPassword); - LOG.info("created ledger ID: {}", lhs[i].getId()); - } - - LOG.info("generating data for reads"); - final CountDownLatch writesCompleteLatch = new CountDownLatch(numEntriesForReads * NUM_OF_LEDGERS); - for (int i = 0; i < numEntriesForReads; i++) { - for (int ledger = 0; ledger < NUM_OF_LEDGERS; ledger++) { - lhs[ledger].asyncAddEntry(data, (rc2, lh, entryId, ctx) -> writesCompleteLatch.countDown(), null); - } - } - writesCompleteLatch.await(); - - LOG.info("issue bunch of async reads"); - final CountDownLatch readsCompleteLatch = new CountDownLatch(numEntriesForReads * NUM_OF_LEDGERS); - for (int i = 0; i < numEntriesForReads; i++) { - for (int ledger = 0; ledger < NUM_OF_LEDGERS; ledger++) { - lhs[ledger].asyncReadEntries(i, i, (rc, lh, seq, ctx) -> readsCompleteLatch.countDown(), null); - } - } - readsCompleteLatch.await(); - LOG.info("reads finished"); - - return bks.getBookieRequestProcessor(); - } - - // here we expect that backpressure is disabled and number of writes in progress - // will exceed the limit - private void doWritesNoBackpressure(final int bkId) throws Exception { - Assert.assertThat("should be only one bookie", - bookieCount(), Matchers.equalTo(1)); - ServerConfiguration conf = killBookie(0); - BookieServer bks = startAndAddBookie(conf, - bookieWithMockedJournal(conf, getDelay, addDelay, flushDelay)) - .getServer(); - - LOG.info("Creating ledgers"); - LedgerHandle[] lhs = new LedgerHandle[NUM_OF_LEDGERS]; - for (int i = 0; i < NUM_OF_LEDGERS; i++) { - lhs[i] = bkc.createLedger(1, 1, digestType, ledgerPassword); - LOG.info("created ledger ID: {}", lhs[i].getId()); - } - - final CountDownLatch completeLatch = new CountDownLatch(NUM_ENTRIES_TO_WRITE * NUM_OF_LEDGERS); - - LOG.info("submitting writes"); - for (int i = 0; i < NUM_ENTRIES_TO_WRITE; i++) { - for (int ledger = 0; ledger < NUM_OF_LEDGERS; ledger++) { - lhs[ledger].asyncAddEntry(data, (rc2, lh, entryId, ctx) -> completeLatch.countDown(), null); - } - } - - boolean exceededLimit = false; - BookieRequestProcessor brp = bks.getBookieRequestProcessor(); - while (!completeLatch.await(1, TimeUnit.MILLISECONDS)) { - int val = brp.maxAddsInProgressCount(); - if (val > MAX_PENDING) { - exceededLimit = true; - break; - } - LOG.info("Waiting until all writes succeeded or maxAddsInProgressCount {} > MAX_PENDING {}", - val, MAX_PENDING); - } - - assertTrue("expected to exceed number of pending writes", exceededLimit); - - for (int i = 0; i < NUM_OF_LEDGERS; i++) { - lhs[i].close(); - } - } - - // here we expect that backpressure is enabled and number of writes in progress - // will never exceed the limit - private void doWritesWithBackpressure(final int bkId) throws Exception { - Assert.assertThat("should be only one bookie", - bookieCount(), Matchers.equalTo(1)); - ServerConfiguration conf = killBookie(0); - BookieServer bks = startAndAddBookie(conf, - bookieWithMockedJournal(conf, getDelay, addDelay, flushDelay)) - .getServer(); - - LOG.info("Creating ledgers"); - LedgerHandle[] lhs = new LedgerHandle[NUM_OF_LEDGERS]; - for (int i = 0; i < NUM_OF_LEDGERS; i++) { - lhs[i] = bkc.createLedger(1, 1, digestType, ledgerPassword); - LOG.info("created ledger ID: {}", lhs[i].getId()); - } - - final CountDownLatch completeLatch = new CountDownLatch(NUM_ENTRIES_TO_WRITE * NUM_OF_LEDGERS); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - - LOG.info("submitting writes"); - for (int i = 0; i < NUM_ENTRIES_TO_WRITE; i++) { - for (int ledger = 0; ledger < NUM_OF_LEDGERS; ledger++) { - lhs[ledger].asyncAddEntry(data, (rc2, lh, entryId, ctx) -> { - rc.compareAndSet(BKException.Code.OK, rc2); - completeLatch.countDown(); - }, null); - } - } - - LOG.info("test submitted all writes"); - BookieRequestProcessor brp = bks.getBookieRequestProcessor(); - while (!completeLatch.await(1, TimeUnit.MILLISECONDS)) { - int val = brp.maxAddsInProgressCount(); - assertTrue("writes in progress should not exceed limit, got " + val, val <= MAX_PENDING); - LOG.info("Waiting for all writes to succeed, left {} of {}", - completeLatch.getCount(), NUM_ENTRIES_TO_WRITE * NUM_OF_LEDGERS); - } - - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - - for (int i = 0; i < NUM_OF_LEDGERS; i++) { - lhs[i].close(); - } - } - - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - SyncObj sync = (SyncObj) ctx; - sync.setReturnCode(rc); - synchronized (sync) { - sync.counter++; - sync.notify(); - } - } - - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - SyncObj sync = (SyncObj) ctx; - sync.setLedgerEntries(seq); - sync.setReturnCode(rc); - synchronized (sync) { - sync.value = true; - sync.notify(); - } - } - - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - SyncObj sync = (SyncObj) ctx; - sync.setReturnCode(rc); - synchronized (sync) { - sync.lastConfirmed = lastConfirmed; - sync.notify(); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java deleted file mode 100644 index 4f719ddfc08..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.proto.BookieProtocol.FLAG_NONE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import com.google.protobuf.ByteString; -import com.google.protobuf.ExtensionRegistry; -import com.google.protobuf.InvalidProtocolBufferException; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.channel.ChannelHandlerContext; -import java.util.List; -import org.apache.bookkeeper.proto.BookieProtoEncoding.RequestEnDeCoderPreV3; -import org.apache.bookkeeper.proto.BookieProtoEncoding.RequestEnDecoderV3; -import org.apache.bookkeeper.proto.BookieProtoEncoding.ResponseDecoder; -import org.apache.bookkeeper.proto.BookieProtoEncoding.ResponseEnDeCoderPreV3; -import org.apache.bookkeeper.proto.BookieProtoEncoding.ResponseEnDecoderV3; -import org.apache.bookkeeper.proto.BookieProtocol.AddResponse; -import org.apache.bookkeeper.proto.BookkeeperProtocol.AddRequest.Flag; -import org.apache.bookkeeper.proto.BookkeeperProtocol.BKPacketHeader; -import org.apache.bookkeeper.proto.BookkeeperProtocol.OperationType; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ProtocolVersion; -import org.apache.bookkeeper.proto.BookkeeperProtocol.StatusCode; -import org.apache.bookkeeper.util.ByteBufList; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link BookieProtoEncoding}. - */ -public class BookieProtoEncodingTest { - - private ExtensionRegistry registry; - - @Before - public void setup() { - this.registry = ExtensionRegistry.newInstance(); - } - - @Test - public void testV3ResponseDecoderNoFallback() throws Exception { - AddResponse v2Resp = AddResponse.create( - BookieProtocol.CURRENT_PROTOCOL_VERSION, - BookieProtocol.EOK, - 1L, - 2L); - - BookkeeperProtocol.Response v3Resp = BookkeeperProtocol.Response.newBuilder() - .setHeader(BKPacketHeader.newBuilder() - .setVersion(ProtocolVersion.VERSION_THREE) - .setTxnId(1L) - .setOperation(OperationType.ADD_ENTRY) - .build()) - .setStatus(StatusCode.EOK) - .setAddResponse(BookkeeperProtocol.AddResponse.newBuilder() - .setStatus(StatusCode.EOK) - .setLedgerId(1L) - .setEntryId(2L) - .build()) - .build(); - - List outList = Lists.newArrayList(); - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.fireChannelRead(any())).thenAnswer((iom) -> { - outList.add(iom.getArgument(0)); - return null; - }); - - ResponseEnDeCoderPreV3 v2Encoder = new ResponseEnDeCoderPreV3(registry); - ResponseEnDecoderV3 v3Encoder = new ResponseEnDecoderV3(registry); - - ResponseDecoder v3Decoder = new ResponseDecoder(registry, false, false); - try { - v3Decoder.channelRead(ctx, - v2Encoder.encode(v2Resp, UnpooledByteBufAllocator.DEFAULT) - ); - fail("V3 response decoder should fail on decoding v2 response"); - } catch (InvalidProtocolBufferException e) { - // expected - } - assertEquals(0, outList.size()); - - ByteBuf serWithFrameSize = (ByteBuf) v3Encoder.encode(v3Resp, UnpooledByteBufAllocator.DEFAULT); - ByteBuf ser = serWithFrameSize.slice(4, serWithFrameSize.readableBytes() - 4); - v3Decoder.channelRead(ctx, ser); - assertEquals(1, outList.size()); - } - - @Test(expected = IllegalStateException.class) - public void testV2RequestDecoderThrowExceptionOnUnknownRequests() throws Exception { - RequestEnDeCoderPreV3 v2ReqEncoder = new RequestEnDeCoderPreV3(registry); - RequestEnDecoderV3 v3ReqEncoder = new RequestEnDecoderV3(registry); - - BookkeeperProtocol.Request v3Req = BookkeeperProtocol.Request.newBuilder() - .setHeader(BKPacketHeader.newBuilder() - .setVersion(ProtocolVersion.VERSION_THREE) - .setTxnId(1L) - .setOperation(OperationType.ADD_ENTRY) - .build()) - .setAddRequest(BookkeeperProtocol.AddRequest.newBuilder() - .setLedgerId(1L) - .setEntryId(2L) - .setMasterKey(ByteString.copyFrom("", UTF_8)) - .setFlag(Flag.RECOVERY_ADD) - .setBody(ByteString.copyFrom("test", UTF_8))) - .build(); - - - v2ReqEncoder.decode((ByteBuf) v3ReqEncoder.encode(v3Req, UnpooledByteBufAllocator.DEFAULT)); - } - - @Test - public void testV2BatchReadRequest() throws Exception { - RequestEnDeCoderPreV3 v2ReqEncoder = new RequestEnDeCoderPreV3(registry); - BookieProtocol.BatchedReadRequest req = BookieProtocol.BatchedReadRequest.create( - BookieProtocol.CURRENT_PROTOCOL_VERSION, 1L, 1L, FLAG_NONE, null, 1L, 10, 1024L); - ByteBuf buf = (ByteBuf) v2ReqEncoder.encode(req, UnpooledByteBufAllocator.DEFAULT); - buf.readInt(); // Skip the frame size. - BookieProtocol.BatchedReadRequest reqDecoded = (BookieProtocol.BatchedReadRequest) v2ReqEncoder.decode(buf); - assertEquals(req.ledgerId, reqDecoded.ledgerId); - assertEquals(req.entryId, reqDecoded.entryId); - assertEquals(req.maxSize, reqDecoded.maxSize); - assertEquals(req.maxCount, reqDecoded.maxCount); - reqDecoded.recycle(); - } - - @Test - public void testV2BatchReadResponse() throws Exception { - ResponseEnDeCoderPreV3 v2ReqEncoder = new ResponseEnDeCoderPreV3(registry); - ByteBuf first = UnpooledByteBufAllocator.DEFAULT.buffer(4).writeInt(10); - ByteBuf second = UnpooledByteBufAllocator.DEFAULT.buffer(8).writeLong(10L); - ByteBufList data = ByteBufList.get(first, second); - BookieProtocol.BatchedReadResponse res = new BookieProtocol.BatchedReadResponse( - BookieProtocol.CURRENT_PROTOCOL_VERSION, 1, 1L, 1L, 1L, data); - ByteBuf buf = (ByteBuf) v2ReqEncoder.encode(res, UnpooledByteBufAllocator.DEFAULT); - buf.readInt(); // Skip the frame size. - BookieProtocol.BatchedReadResponse resDecoded = (BookieProtocol.BatchedReadResponse) v2ReqEncoder.decode(buf); - assertEquals(res.ledgerId, resDecoded.ledgerId); - assertEquals(res.entryId, resDecoded.entryId); - assertEquals(res.getData().size(), resDecoded.getData().size()); - assertEquals(res.getData().readableBytes(), resDecoded.getData().readableBytes()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ForceLedgerProcessorV3Test.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ForceLedgerProcessorV3Test.java deleted file mode 100644 index 3bc9cbee427..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ForceLedgerProcessorV3Test.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.channel.DefaultChannelPromise; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.proto.BookkeeperProtocol.BKPacketHeader; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ForceLedgerRequest; -import org.apache.bookkeeper.proto.BookkeeperProtocol.OperationType; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ProtocolVersion; -import org.apache.bookkeeper.proto.BookkeeperProtocol.Request; -import org.apache.bookkeeper.proto.BookkeeperProtocol.Response; -import org.apache.bookkeeper.proto.BookkeeperProtocol.StatusCode; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link ForceLedgerProcessorV3}. - */ -public class ForceLedgerProcessorV3Test { - - private Request request; - private ForceLedgerProcessorV3 processor; - - private BookieRequestHandler requestHandler; - private Channel channel; - private BookieRequestProcessor requestProcessor; - private Bookie bookie; - - @Before - public void setup() { - request = Request.newBuilder() - .setHeader(BKPacketHeader.newBuilder() - .setTxnId(System.currentTimeMillis()) - .setVersion(ProtocolVersion.VERSION_THREE) - .setOperation(OperationType.ADD_ENTRY) - .build()) - .setForceLedgerRequest(ForceLedgerRequest.newBuilder() - .setLedgerId(System.currentTimeMillis()) - .build()) - .build(); - - - channel = mock(Channel.class); - when(channel.isOpen()).thenReturn(true); - when(channel.isActive()).thenReturn(true); - - requestHandler = mock(BookieRequestHandler.class); - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - when(requestHandler.ctx()).thenReturn(ctx); - - bookie = mock(Bookie.class); - requestProcessor = mock(BookieRequestProcessor.class); - when(requestProcessor.getBookie()).thenReturn(bookie); - when(requestProcessor.getWaitTimeoutOnBackpressureMillis()).thenReturn(-1L); - when(requestProcessor.getRequestStats()).thenReturn(new RequestStats(NullStatsLogger.INSTANCE)); - processor = new ForceLedgerProcessorV3( - request, - requestHandler, - requestProcessor); - } - - @Test - public void testForceLedger() throws Exception { - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - when(channel.writeAndFlush(any())).thenReturn(mock(ChannelPromise.class)); - doAnswer(invocationOnMock -> { - WriteCallback wc = invocationOnMock.getArgument(1); - - wc.writeComplete( - 0, - request.getForceLedgerRequest().getLedgerId(), - BookieImpl.METAENTRY_ID_FORCE_LEDGER, - null, - null); - return null; - }).when(bookie).forceLedger( - eq(request.getForceLedgerRequest().getLedgerId()), - any(WriteCallback.class), - same(requestHandler)); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any()); - - processor.run(); - - verify(bookie, times(1)) - .forceLedger(eq(request.getForceLedgerRequest().getLedgerId()), - any(WriteCallback.class), same(requestHandler)); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(StatusCode.EOK, response.getStatus()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/GetBookieInfoProcessorV3Test.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/GetBookieInfoProcessorV3Test.java deleted file mode 100644 index 5e986515e92..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/GetBookieInfoProcessorV3Test.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link GetBookieInfoProcessorV3}. - */ -public class GetBookieInfoProcessorV3Test { - - private BookieRequestHandler requestHandler; - private Channel channel; - private BookieRequestProcessor requestProcessor; - private Bookie bookie; - private RequestStats requestStats; - private OpStatsLogger getBookieInfoStats; - private OpStatsLogger channelWriteStats; - private OpStatsLogger getBookieInfoRequestStats; - - @Before - public void setup() { - getBookieInfoStats = mock(OpStatsLogger.class); - channelWriteStats = mock(OpStatsLogger.class); - getBookieInfoRequestStats = mock(OpStatsLogger.class); - requestStats = mock(RequestStats.class); - requestProcessor = mock(BookieRequestProcessor.class); - bookie = mock(Bookie.class); - when(requestProcessor.getBookie()).thenReturn(bookie); - - requestHandler = mock(BookieRequestHandler.class); - - channel = mock(Channel.class); - when(channel.isOpen()).thenReturn(true); - when(channel.isActive()).thenReturn(true); - - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - when(requestHandler.ctx()).thenReturn(ctx); - - when(requestProcessor.getRequestStats()).thenReturn(requestStats); - when(requestProcessor.getRequestStats().getGetBookieInfoStats()) - .thenReturn(getBookieInfoStats); - when(requestProcessor.getRequestStats().getChannelWriteStats()) - .thenReturn(channelWriteStats); - when(requestProcessor.getRequestStats().getGetBookieInfoRequestStats()) - .thenReturn(getBookieInfoRequestStats); - } - - @Test - public void testGetBookieInfoProcessorStats() throws IOException { - final BookkeeperProtocol.BKPacketHeader.Builder headerBuilder = - BookkeeperProtocol.BKPacketHeader.newBuilder() - .setVersion(BookkeeperProtocol.ProtocolVersion.VERSION_THREE) - .setOperation(BookkeeperProtocol.OperationType.GET_BOOKIE_INFO) - .setTxnId(0); - - final BookkeeperProtocol.GetBookieInfoRequest.Builder getBookieInfoBuilder = - BookkeeperProtocol.GetBookieInfoRequest.newBuilder() - .setRequested(BookkeeperProtocol.GetBookieInfoRequest.Flags.FREE_DISK_SPACE_VALUE); - - final BookkeeperProtocol.Request getBookieInfoRequest = BookkeeperProtocol.Request.newBuilder() - .setHeader(headerBuilder) - .setGetBookieInfoRequest(getBookieInfoBuilder) - .build(); - - GetBookieInfoProcessorV3 getBookieInfo = new GetBookieInfoProcessorV3( - getBookieInfoRequest, requestHandler, requestProcessor); - getBookieInfo.run(); - - // get BookieInfo succeeded. - verify(getBookieInfoStats, times(1)) - .registerSuccessfulEvent(anyLong(), eq(TimeUnit.NANOSECONDS)); - - // get BookieInfo failed. - when(requestProcessor.getBookie().getTotalFreeSpace()).thenThrow(new IOException("test for failed.")); - getBookieInfo.run(); - verify(getBookieInfoStats, times(1)) - .registerFailedEvent(anyLong(), eq(TimeUnit.NANOSECONDS)); - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/LongPollReadEntryProcessorV3Test.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/LongPollReadEntryProcessorV3Test.java deleted file mode 100644 index 33a4fdc8295..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/LongPollReadEntryProcessorV3Test.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.protobuf.ByteString; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.util.HashedWheelTimer; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.proto.BookkeeperProtocol.BKPacketHeader; -import org.apache.bookkeeper.proto.BookkeeperProtocol.OperationType; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ProtocolVersion; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ReadRequest; -import org.apache.bookkeeper.proto.BookkeeperProtocol.Request; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - - - - -/** - * Unit test {@link LongPollReadEntryProcessorV3}. - */ -public class LongPollReadEntryProcessorV3Test { - ExecutorService executor; - HashedWheelTimer timer; - - @Before - public void setup() { - executor = Executors.newSingleThreadExecutor(); - timer = new HashedWheelTimer(); - } - - @After - public void teardown() { - timer.stop(); - executor.shutdownNow(); - } - - @Test - public void testWatchIsCancelledOnTimeout() throws Exception { - Request request = Request.newBuilder() - .setHeader(BKPacketHeader.newBuilder() - .setTxnId(System.currentTimeMillis()) - .setVersion(ProtocolVersion.VERSION_THREE) - .setOperation(OperationType.READ_ENTRY) - .build()) - .setReadRequest(ReadRequest.newBuilder() - .setLedgerId(10) - .setEntryId(1) - .setMasterKey(ByteString.copyFrom(new byte[0])) - .setPreviousLAC(0) - .setTimeOut(1) - .build()) - .build(); - - Channel channel = mock(Channel.class); - when(channel.isOpen()).thenReturn(true); - - BookieRequestHandler requestHandler = mock(BookieRequestHandler.class); - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - when(requestHandler.ctx()).thenReturn(ctx); - - Bookie bookie = mock(Bookie.class); - - BookieRequestProcessor requestProcessor = mock(BookieRequestProcessor.class); - when(requestProcessor.getBookie()).thenReturn(bookie); - when(requestProcessor.getRequestStats()).thenReturn(new RequestStats(NullStatsLogger.INSTANCE)); - - when(bookie.waitForLastAddConfirmedUpdate(anyLong(), anyLong(), any())) - .thenReturn(true); - when(bookie.readEntry(anyLong(), anyLong())).thenReturn(Unpooled.buffer()); - when(bookie.readLastAddConfirmed(anyLong())).thenReturn(Long.valueOf(1)); - - CompletableFuture cancelFuture = new CompletableFuture<>(); - - doAnswer(invocationOnMock -> { - cancelFuture.complete(null); - return null; - }).when(bookie).cancelWaitForLastAddConfirmedUpdate(anyLong(), any()); - - LongPollReadEntryProcessorV3 processor = new LongPollReadEntryProcessorV3( - request, - requestHandler, - requestProcessor, - executor, executor, timer); - - processor.run(); - - cancelFuture.get(10, TimeUnit.SECONDS); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookieClient.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookieClient.java deleted file mode 100644 index 37317317475..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookieClient.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.proto; - -import static org.apache.bookkeeper.proto.BookieProtocol.FLAG_RECOVERY_ADD; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCounted; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import lombok.Getter; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ForceLedgerCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.FutureGetListOfEntriesOfLedger; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GetBookieInfoCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadLacCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteLacCallback; -import org.apache.bookkeeper.util.AvailabilityOfEntriesOfLedger; -import org.apache.bookkeeper.util.ByteBufList; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Mock implementation of BookieClient. - */ -public class MockBookieClient implements BookieClient { - static final Logger LOG = LoggerFactory.getLogger(MockBookieClient.class); - - @Getter - final OrderedExecutor executor; - final MockBookies mockBookies; - final Set errorBookies = - Collections.newSetFromMap(new ConcurrentHashMap<>()); - - /** - * Runs before or after an operation. Can stall the operation or error it. - */ - public interface Hook { - CompletableFuture runHook(BookieId bookie, long ledgerId, long entryId); - } - - /** - * Runs before or after an operation. Can stall the operation or error it. - */ - public interface BatchHook { - CompletableFuture runHook(BookieId bookie, long ledgerId, long startEntryId, int maxCount, long maxSize); - } - - private Hook preReadHook = (bookie, ledgerId, entryId) -> FutureUtils.value(null); - private Hook postReadHook = (bookie, ledgerId, entryId) -> FutureUtils.value(null); - private Hook preWriteHook = (bookie, ledgerId, entryId) -> FutureUtils.value(null); - private Hook postWriteHook = (bookie, ledgerId, entryId) -> FutureUtils.value(null); - private BatchHook preBatchReadHook = (bookie, ledgerId, startEntryId, maxCount, maxSize) -> FutureUtils.value(null); - private BatchHook postBatchReadHook = (bookie, ledgerId, startEntryId, maxCount, maxSize) -> FutureUtils.value( - null); - - public MockBookieClient(OrderedExecutor executor) { - this.executor = executor; - this.mockBookies = new MockBookies(); - } - - public MockBookieClient(OrderedExecutor executor, - MockBookies mockBookies) { - this.executor = executor; - this.mockBookies = mockBookies; - } - - public void setPreReadHook(Hook hook) { - this.preReadHook = hook; - } - - public void setPostReadHook(Hook hook) { - this.postReadHook = hook; - } - - public void setPreWriteHook(Hook hook) { - this.preWriteHook = hook; - } - - public void setPostWriteHook(Hook hook) { - this.postWriteHook = hook; - } - - public void errorBookies(BookieId... bookies) { - errorBookies.addAll(Arrays.asList(bookies)); - } - - public void removeErrors(BookieId... bookies) { - for (BookieId b : bookies) { - errorBookies.remove(b); - } - } - - public boolean isErrored(BookieId bookieId) { - return errorBookies.contains(bookieId); - } - - public MockBookies getMockBookies() { - return mockBookies; - } - - @Override - public List getFaultyBookies() { - return Collections.emptyList(); - } - - @Override - public boolean isWritable(BookieId address, long ledgerId) { - return true; - } - - @Override - public long getNumPendingRequests(BookieId address, long ledgerId) { - return 0; - } - - @Override - public void forceLedger(BookieId addr, long ledgerId, - ForceLedgerCallback cb, Object ctx) { - executor.executeOrdered(ledgerId, - () -> cb.forceLedgerComplete(BKException.Code.IllegalOpException, ledgerId, addr, ctx)); - } - - @Override - public void writeLac(BookieId addr, long ledgerId, byte[] masterKey, - long lac, ByteBufList toSend, WriteLacCallback cb, Object ctx) { - executor.executeOrdered(ledgerId, - () -> cb.writeLacComplete(BKException.Code.IllegalOpException, ledgerId, addr, ctx)); - } - - @Override - public void addEntry(BookieId addr, long ledgerId, byte[] masterKey, - long entryId, ReferenceCounted toSend, WriteCallback cb, Object ctx, - int options, boolean allowFastFail, EnumSet writeFlags) { - toSend.retain(); - preWriteHook.runHook(addr, ledgerId, entryId) - .thenComposeAsync( - (ignore) -> { - LOG.info("[{};L{}] write entry {}", addr, ledgerId, entryId); - if (isErrored(addr)) { - LOG.warn("[{};L{}] erroring write {}", addr, ledgerId, entryId); - return FutureUtils.exception(new BKException.BKWriteException()); - } - - try { - if ((options & FLAG_RECOVERY_ADD) == FLAG_RECOVERY_ADD) { - mockBookies.recoveryAddEntry(addr, ledgerId, entryId, copyData(toSend)); - } else { - mockBookies.addEntry(addr, ledgerId, entryId, copyData(toSend)); - } - } catch (BKException bke) { - return FutureUtils.exception(bke); - } finally { - toSend.release(); - } - - return FutureUtils.value(null); - }, executor.chooseThread(ledgerId)) - .thenCompose((res) -> postWriteHook.runHook(addr, ledgerId, entryId)) - .whenCompleteAsync((res, ex) -> { - if (ex != null) { - cb.writeComplete(BKException.getExceptionCode(ex, BKException.Code.WriteException), - ledgerId, entryId, addr, ctx); - } else { - cb.writeComplete(BKException.Code.OK, ledgerId, entryId, addr, ctx); - } - }, executor.chooseThread(ledgerId)); - } - - @Override - public void readLac(BookieId addr, long ledgerId, ReadLacCallback cb, Object ctx) { - executor.executeOrdered(ledgerId, - () -> cb.readLacComplete(BKException.Code.IllegalOpException, ledgerId, null, null, ctx)); - } - - @Override - public void readEntry(BookieId addr, long ledgerId, long entryId, - ReadEntryCallback cb, Object ctx, int flags, byte[] masterKey, - boolean allowFastFail) { - preReadHook.runHook(addr, ledgerId, entryId) - .thenComposeAsync((res) -> { - LOG.info("[{};L{}] read entry {}", addr, ledgerId, entryId); - if (isErrored(addr)) { - LOG.warn("[{};L{}] erroring read {}", addr, ledgerId, entryId); - return FutureUtils.exception(new BKException.BKReadException()); - } - - try { - ByteBuf entry = mockBookies.readEntry(addr, flags, ledgerId, entryId); - return FutureUtils.value(entry); - } catch (BKException bke) { - return FutureUtils.exception(bke); - } - }, executor.chooseThread(ledgerId)) - .thenCompose((buf) -> postReadHook.runHook(addr, ledgerId, entryId).thenApply((res) -> buf)) - .whenCompleteAsync((res, ex) -> { - if (ex != null) { - cb.readEntryComplete(BKException.getExceptionCode(ex, BKException.Code.ReadException), - ledgerId, entryId, null, ctx); - } else { - cb.readEntryComplete(BKException.Code.OK, - ledgerId, entryId, res.slice(), ctx); - } - }, executor.chooseThread(ledgerId)); - } - - @Override - public void batchReadEntries(BookieId addr, long ledgerId, long startEntryId, int maxCount, long maxSize, - BookkeeperInternalCallbacks.BatchedReadEntryCallback cb, Object ctx, int flags, byte[] masterKey, - boolean allowFastFail) { - preBatchReadHook.runHook(addr, ledgerId, startEntryId, maxCount, maxSize) - .thenComposeAsync((res) -> { - LOG.info("[{};L{}] batch read entries startEntryId:{} maxCount:{} maxSize:{}", - addr, ledgerId, startEntryId, maxCount, maxSize); - if (isErrored(addr)) { - LOG.warn("[{};L{}] erroring batch read entries startEntryId:{} maxCount:{} maxSize:{}", - addr, ledgerId, startEntryId, maxCount, maxSize); - return FutureUtils.exception(new BKException.BKReadException()); - } - - try { - ByteBufList data = mockBookies.batchReadEntries(addr, flags, ledgerId, startEntryId, - maxCount, maxSize); - return FutureUtils.value(data); - } catch (BKException bke) { - return FutureUtils.exception(bke); - } - }, executor.chooseThread(ledgerId)) - .thenCompose((buf) -> postBatchReadHook.runHook(addr, ledgerId, startEntryId, maxCount, maxSize) - .thenApply((res) -> buf)) - .whenCompleteAsync((res, ex) -> { - if (ex != null) { - cb.readEntriesComplete(BKException.getExceptionCode(ex, BKException.Code.ReadException), - ledgerId, startEntryId, null, ctx); - } else { - cb.readEntriesComplete(BKException.Code.OK, - ledgerId, startEntryId, res, ctx); - } - }, executor.chooseThread(ledgerId)); - } - - @Override - public void readEntryWaitForLACUpdate(BookieId addr, - long ledgerId, - long entryId, - long previousLAC, - long timeOutInMillis, - boolean piggyBackEntry, - ReadEntryCallback cb, - Object ctx) { - executor.executeOrdered(ledgerId, - () -> cb.readEntryComplete(BKException.Code.IllegalOpException, ledgerId, entryId, null, ctx)); - } - - @Override - public void getBookieInfo(BookieId addr, long requested, - GetBookieInfoCallback cb, Object ctx) { - executor.executeOrdered(addr, - () -> cb.getBookieInfoComplete(BKException.Code.IllegalOpException, null, ctx)); - } - - @Override - public CompletableFuture getListOfEntriesOfLedger(BookieId address, - long ledgerId) { - FutureGetListOfEntriesOfLedger futureResult = new FutureGetListOfEntriesOfLedger(ledgerId); - executor.executeOrdered(address, () -> - futureResult.completeExceptionally( - BKException.create(BKException.Code.IllegalOpException).fillInStackTrace()) - ); - return futureResult; - } - - @Override - public boolean isClosed() { - return false; - } - - @Override - public void close() { - } - - public static ByteBuf copyData(ReferenceCounted rc) { - ByteBuf res; - if (rc instanceof ByteBuf) { - res = Unpooled.copiedBuffer((ByteBuf) rc); - } else { - res = ByteBufList.coalesce((ByteBufList) rc); - } - - return res; - } - - public static ByteBuf copyDataWithSkipHeader(ReferenceCounted rc) { - ByteBuf res; - if (rc instanceof ByteBuf) { - res = Unpooled.copiedBuffer((ByteBuf) rc); - } else { - res = ByteBufList.coalesce((ByteBufList) rc); - } - - // Skip headers - res.skipBytes(28); - rc.release(); - - return res; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookies.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookies.java deleted file mode 100644 index ac338b9757d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookies.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.proto; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BiPredicate; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.DistributionSchedule; -import org.apache.bookkeeper.client.RoundRobinDistributionSchedule; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.util.ByteBufList; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Mocks an ensemble of bookies and can be shared between more than one MockBookieClient - * so that it can be used to check two writers accessing the same ledger. - */ -public class MockBookies { - static final Logger LOG = LoggerFactory.getLogger(MockBookies.class); - final ConcurrentHashMap> data = new ConcurrentHashMap<>(); - - public void seedLedgerForBookie(BookieId bookieId, long ledgerId, - LedgerMetadata metadata) throws Exception { - seedLedgerBase(ledgerId, metadata, (bookie, entry) -> bookie.equals(bookieId)); - } - - public void seedLedger(long ledgerId, LedgerMetadata metadata) throws Exception { - seedLedgerBase(ledgerId, metadata, (bookie, entry) -> true); - } - - public void seedLedgerBase(long ledgerId, LedgerMetadata metadata, - BiPredicate shouldSeed) throws Exception { - DistributionSchedule schedule = new RoundRobinDistributionSchedule(metadata.getWriteQuorumSize(), - metadata.getAckQuorumSize(), - metadata.getEnsembleSize()); - long lastEntry = metadata.isClosed() - ? metadata.getLastEntryId() : metadata.getAllEnsembles().lastEntry().getKey() - 1; - long lac = -1; - for (long e = 0; e <= lastEntry; e++) { - List ensemble = metadata.getEnsembleAt(e); - DistributionSchedule.WriteSet ws = schedule.getWriteSet(e); - for (int i = 0; i < ws.size(); i++) { - BookieId bookieId = ensemble.get(ws.get(i)); - if (shouldSeed.test(bookieId, e)) { - seedEntries(bookieId, ledgerId, e, lac); - } - } - lac = e; - } - } - - public void seedEntries(BookieId bookieId, long ledgerId, long entryId, long lac) throws Exception { - ByteBuf entry = generateEntry(ledgerId, entryId, lac); - MockLedgerData ledger = getBookieData(bookieId).computeIfAbsent(ledgerId, MockLedgerData::new); - ledger.addEntry(entryId, entry); - } - - public ByteBuf generateEntry(long ledgerId, long entryId, long lac) throws Exception { - DigestManager digestManager = DigestManager.instantiate(ledgerId, new byte[0], - DataFormats.LedgerMetadataFormat.DigestType.CRC32C, - UnpooledByteBufAllocator.DEFAULT, false); - return ByteBufList.coalesce((ByteBufList) digestManager.computeDigestAndPackageForSending( - entryId, lac, 0, Unpooled.buffer(10), new byte[20], 0)); - - } - - public void addEntry(BookieId bookieId, long ledgerId, long entryId, ByteBuf entry) throws BKException { - MockLedgerData ledger = getBookieData(bookieId).computeIfAbsent(ledgerId, MockLedgerData::new); - if (ledger.isFenced()) { - throw new BKException.BKLedgerFencedException(); - } - ledger.addEntry(entryId, entry); - } - - public void recoveryAddEntry(BookieId bookieId, long ledgerId, long entryId, ByteBuf entry) throws BKException { - MockLedgerData ledger = getBookieData(bookieId).computeIfAbsent(ledgerId, MockLedgerData::new); - ledger.addEntry(entryId, entry); - } - - public ByteBuf readEntry(BookieId bookieId, int flags, long ledgerId, long entryId) throws BKException { - MockLedgerData ledger = getBookieData(bookieId).get(ledgerId); - - if (ledger == null) { - LOG.warn("[{};L{}] ledger not found", bookieId, ledgerId); - throw new BKException.BKNoSuchLedgerExistsException(); - } - - if ((flags & BookieProtocol.FLAG_DO_FENCING) == BookieProtocol.FLAG_DO_FENCING) { - ledger.fence(); - } - - ByteBuf entry = ledger.getEntry(entryId); - if (entry == null) { - LOG.warn("[{};L{}] entry({}) not found", bookieId, ledgerId, entryId); - throw new BKException.BKNoSuchEntryException(); - } - - return entry; - } - - public ByteBufList batchReadEntries(BookieId bookieId, int flags, long ledgerId, long startEntryId, - int maxCount, long maxSize) throws BKException { - MockLedgerData ledger = getBookieData(bookieId).get(ledgerId); - - if (ledger == null) { - LOG.warn("[{};L{}] ledger not found", bookieId, ledgerId); - throw new BKException.BKNoSuchLedgerExistsException(); - } - - if ((flags & BookieProtocol.FLAG_DO_FENCING) == BookieProtocol.FLAG_DO_FENCING) { - ledger.fence(); - } - //Refer: BatchedReadEntryProcessor.readData - ByteBufList data = null; - if (maxCount <= 0) { - maxCount = Integer.MAX_VALUE; - } - long frameSize = 24 + 8 + 4; - for (long i = startEntryId; i < startEntryId + maxCount; i++) { - ByteBuf entry = ledger.getEntry(i); - frameSize += entry.readableBytes() + 4; - if (data == null) { - data = ByteBufList.get(entry); - } else { - if (frameSize > maxSize) { - entry.release(); - break; - } - data.add(entry); - } - } - return data; - } - - public ConcurrentHashMap getBookieData(BookieId bookieId) { - return data.computeIfAbsent(bookieId, (key) -> new ConcurrentHashMap<>()); - } - - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockLedgerData.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockLedgerData.java deleted file mode 100644 index 99f27d12284..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockLedgerData.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.proto; - -import io.netty.buffer.ByteBuf; -import java.util.Map; -import java.util.TreeMap; - -/** - Mock ledger data. - */ -public class MockLedgerData { - final long ledgerId; - boolean isFenced; - private TreeMap entries = new TreeMap<>(); - - MockLedgerData(long ledgerId) { - this.ledgerId = ledgerId; - } - - boolean isFenced() { - return isFenced; - } - - void fence() { - isFenced = true; - } - - void addEntry(long entryId, ByteBuf entry) { - entries.put(entryId, entry); - } - - ByteBuf getEntry(long entryId) { - if (entryId == BookieProtocol.LAST_ADD_CONFIRMED) { - Map.Entry lastEntry = entries.lastEntry(); - if (lastEntry != null) { - return lastEntry.getValue(); - } else { - return null; - } - } else { - return entries.get(entryId); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/NetworkLessBookieTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/NetworkLessBookieTest.java deleted file mode 100644 index 990838073a4..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/NetworkLessBookieTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF 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. -* -*/ - -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.fail; - -import io.netty.channel.Channel; -import io.netty.channel.local.LocalChannel; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Tests of the main BookKeeper client using networkless comunication. - */ -public class NetworkLessBookieTest extends BookKeeperClusterTestCase { - - public NetworkLessBookieTest() { - super(1); - baseConf.setDisableServerSocketBind(true); - baseConf.setEnableLocalTransport(true); - } - - @Test - public void testUseLocalBookie() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - conf.setZkTimeout(20000); - - try (BookKeeper bkc = new BookKeeper(conf)) { - try (LedgerHandle h = bkc.createLedger(1, 1, DigestType.CRC32, "testPasswd".getBytes())) { - h.addEntry("test".getBytes()); - } - } - - for (int i = 0; i < bookieCount(); i++) { - for (Channel channel : serverByIndex(i).nettyServer.allChannels) { - if (!(channel instanceof LocalChannel)) { - fail(); - } - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ReadEntryProcessorTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ReadEntryProcessorTest.java deleted file mode 100644 index 251f900c096..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ReadEntryProcessorTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.channel.DefaultChannelPromise; -import io.netty.channel.EventLoop; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.proto.BookieProtocol.ReadRequest; -import org.apache.bookkeeper.proto.BookieProtocol.Response; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link ReadEntryProcessor}. - */ -public class ReadEntryProcessorTest { - - private Channel channel; - private BookieRequestHandler requestHandler; - private BookieRequestProcessor requestProcessor; - private Bookie bookie; - - @Before - public void setup() throws IOException, BookieException { - channel = mock(Channel.class); - when(channel.isOpen()).thenReturn(true); - - requestHandler = mock(BookieRequestHandler.class); - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - when(requestHandler.ctx()).thenReturn(ctx); - - bookie = mock(Bookie.class); - requestProcessor = mock(BookieRequestProcessor.class); - when(requestProcessor.getBookie()).thenReturn(bookie); - when(requestProcessor.getWaitTimeoutOnBackpressureMillis()).thenReturn(-1L); - when(requestProcessor.getRequestStats()).thenReturn(new RequestStats(NullStatsLogger.INSTANCE)); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - when(channel.writeAndFlush(any())).thenReturn(mock(ChannelPromise.class)); - - EventLoop eventLoop = mock(EventLoop.class); - when(eventLoop.inEventLoop()).thenReturn(true); - when(channel.eventLoop()).thenReturn(eventLoop); - } - - @Test - public void testSuccessfulAsynchronousFenceRequest() throws Exception { - testAsynchronousRequest(true, BookieProtocol.EOK); - } - - @Test - public void testFailedAsynchronousFenceRequest() throws Exception { - testAsynchronousRequest(false, BookieProtocol.EIO); - } - - private void testAsynchronousRequest(boolean result, int errorCode) throws Exception { - CompletableFuture fenceResult = FutureUtils.createFuture(); - when(bookie.fenceLedger(anyLong(), any())).thenReturn(fenceResult); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - promise.setSuccess(); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any(Response.class)); - - ExecutorService service = Executors.newCachedThreadPool(); - long ledgerId = System.currentTimeMillis(); - ReadRequest request = ReadRequest.create(BookieProtocol.CURRENT_PROTOCOL_VERSION, ledgerId, - 1, BookieProtocol.FLAG_DO_FENCING, new byte[]{}); - ReadEntryProcessor processor = ReadEntryProcessor.create( - request, requestHandler, requestProcessor, service, true); - processor.run(); - - fenceResult.complete(result); - latch.await(); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(1, response.getEntryId()); - assertEquals(ledgerId, response.getLedgerId()); - assertEquals(BookieProtocol.READENTRY, response.getOpCode()); - assertEquals(errorCode, response.getErrorCode()); - service.shutdown(); - } - - @Test - public void testSuccessfulSynchronousFenceRequest() throws Exception { - testSynchronousRequest(true, BookieProtocol.EOK); - } - - @Test - public void testFailedSynchronousFenceRequest() throws Exception { - testSynchronousRequest(false, BookieProtocol.EIO); - } - - private void testSynchronousRequest(boolean result, int errorCode) throws Exception { - CompletableFuture fenceResult = FutureUtils.createFuture(); - when(bookie.fenceLedger(anyLong(), any())).thenReturn(fenceResult); - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - promise.setSuccess(); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any(Response.class)); - - long ledgerId = System.currentTimeMillis(); - ReadRequest request = ReadRequest.create(BookieProtocol.CURRENT_PROTOCOL_VERSION, ledgerId, - 1, BookieProtocol.FLAG_DO_FENCING, new byte[]{}); - ReadEntryProcessor processor = ReadEntryProcessor.create(request, requestHandler, requestProcessor, null, true); - fenceResult.complete(result); - processor.run(); - - latch.await(); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(1, response.getEntryId()); - assertEquals(ledgerId, response.getLedgerId()); - assertEquals(BookieProtocol.READENTRY, response.getOpCode()); - assertEquals(errorCode, response.getErrorCode()); - } - - @Test - public void testNonFenceRequest() throws Exception { - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - promise.setSuccess(); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any(Response.class)); - - long ledgerId = System.currentTimeMillis(); - ReadRequest request = ReadRequest.create(BookieProtocol.CURRENT_PROTOCOL_VERSION, ledgerId, - 1, (short) 0, new byte[]{}); - ReadEntryProcessor processor = ReadEntryProcessor.create(request, requestHandler, requestProcessor, null, true); - processor.run(); - - latch.await(); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(1, response.getEntryId()); - assertEquals(ledgerId, response.getLedgerId()); - assertEquals(BookieProtocol.READENTRY, response.getOpCode()); - assertEquals(BookieProtocol.EOK, response.getErrorCode()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBKStats.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBKStats.java deleted file mode 100644 index 68d1b04c732..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBKStats.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertEquals; - -import org.apache.bookkeeper.proto.BKStats.OpStats; -import org.junit.Test; - -/** - * Tests that Statistics updation in Bookie Server. - */ -public class TestBKStats { - - /** - * Tests that updatLatency should not fail with - * ArrayIndexOutOfBoundException when latency time coming as negative. - */ - @Test - public void testUpdateLatencyShouldNotFailWithAIOBEWithNegativeLatency() - throws Exception { - OpStats opStat = new OpStats(); - opStat.updateLatency(-10); - assertEquals("Should not update any latency metrics", 0, - opStat.numSuccessOps); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBackwardCompatCMS42.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBackwardCompatCMS42.java deleted file mode 100644 index 1edd74c1fc6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBackwardCompatCMS42.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.protobuf.ByteString; -import com.google.protobuf.ExtensionRegistry; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.auth.AuthProviderFactoryFactory; -import org.apache.bookkeeper.auth.ClientAuthProvider; -import org.apache.bookkeeper.auth.TestAuth; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieProtocol.AuthRequest; -import org.apache.bookkeeper.proto.BookieProtocol.AuthResponse; -import org.apache.bookkeeper.proto.BookieProtocol.ReadRequest; -import org.apache.bookkeeper.proto.BookieProtocol.Request; -import org.apache.bookkeeper.proto.BookieProtocol.Response; -import org.apache.bookkeeper.proto.BookkeeperProtocol.AuthMessage; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Test backward compatibility. - */ -public class TestBackwardCompatCMS42 extends BookKeeperClusterTestCase { - - private static final byte[] SUCCESS_RESPONSE = {1}; - private static final byte[] FAILURE_RESPONSE = {2}; - private static final byte[] PAYLOAD_MESSAGE = {3}; - - ExtensionRegistry extRegistry = ExtensionRegistry.newInstance(); - ClientAuthProvider.Factory authProvider; - EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); - OrderedExecutor executor = OrderedExecutor.newBuilder().numThreads(1).name("TestBackwardCompatClient") - .build(); - - public TestBackwardCompatCMS42() throws Exception { - super(0); - - baseConf.setGcWaitTime(60000); - authProvider = AuthProviderFactoryFactory.newClientAuthProviderFactory( - new ClientConfiguration()); - } - - @Test - public void testAuthSingleMessage() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - TestAuth.AlwaysSucceedBookieAuthProviderFactory.class.getName()); - BookieServer bookie1 = startAndStoreBookie(bookieConf); - - AuthMessage.Builder builder = AuthMessage.newBuilder() - .setAuthPluginName(TestAuth.TEST_AUTH_PROVIDER_PLUGIN_NAME); - builder.setPayload(ByteString.copyFrom(PAYLOAD_MESSAGE)); - final AuthMessage authMessage = builder.build(); - - CompatClient42 client = newCompatClient(bookie1.getBookieId()); - - Request request = new AuthRequest(BookieProtocol.CURRENT_PROTOCOL_VERSION, authMessage); - client.sendRequest(request); - - Response response = client.takeResponse(); - assertTrue("Should be auth response", response instanceof AuthResponse); - assertEquals("Should have succeeded", response.getErrorCode(), BookieProtocol.EOK); - } - - @Test - public void testAuthMultiMessage() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - TestAuth.SucceedAfter3BookieAuthProviderFactory.class.getName()); - BookieServer bookie1 = startAndStoreBookie(bookieConf); - - AuthMessage.Builder builder = AuthMessage.newBuilder() - .setAuthPluginName(TestAuth.TEST_AUTH_PROVIDER_PLUGIN_NAME); - builder.setPayload(ByteString.copyFrom(PAYLOAD_MESSAGE)); - final AuthMessage authMessage = builder.build(); - CompatClient42 client = newCompatClient(bookie1.getBookieId()); - - Request request = new AuthRequest(BookieProtocol.CURRENT_PROTOCOL_VERSION, authMessage); - for (int i = 0; i < 3; i++) { - client.sendRequest(request); - Response response = client.takeResponse(); - assertTrue("Should be auth response", response instanceof AuthResponse); - AuthResponse authResponse = (AuthResponse) response; - assertEquals("Should have succeeded", - response.getErrorCode(), BookieProtocol.EOK); - byte[] type = authResponse.getAuthMessage() - .getPayload().toByteArray(); - if (i == 2) { - assertArrayEquals("Should succeed after 3", - type, SUCCESS_RESPONSE); - } else { - assertArrayEquals("Should be payload", type, - PAYLOAD_MESSAGE); - } - } - } - - @Test - public void testAuthFail() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - TestAuth.FailAfter3BookieAuthProviderFactory.class.getName()); - BookieServer bookie1 = startAndStoreBookie(bookieConf); - - AuthMessage.Builder builder = AuthMessage.newBuilder() - .setAuthPluginName(TestAuth.TEST_AUTH_PROVIDER_PLUGIN_NAME); - builder.setPayload(ByteString.copyFrom(PAYLOAD_MESSAGE)); - final AuthMessage authMessage = builder.build(); - CompatClient42 client = newCompatClient(bookie1.getBookieId()); - - Request request = new AuthRequest(BookieProtocol.CURRENT_PROTOCOL_VERSION, authMessage); - for (int i = 0; i < 3; i++) { - client.sendRequest(request); - Response response = client.takeResponse(); - assertTrue("Should be auth response", response instanceof AuthResponse); - AuthResponse authResponse = (AuthResponse) response; - assertEquals("Should have succeeded", - response.getErrorCode(), BookieProtocol.EOK); - byte[] type = authResponse.getAuthMessage() - .getPayload().toByteArray(); - if (i == 2) { - assertArrayEquals("Should fail after 3", - type, FAILURE_RESPONSE); - } else { - assertArrayEquals("Should be payload", type, - PAYLOAD_MESSAGE); - } - - } - - ReadRequest read = ReadRequest.create(BookieProtocol.CURRENT_PROTOCOL_VERSION, - 1L, 1L, (short) 0, null); - client.sendRequest(read); - Response response = client.takeResponse(); - assertEquals("Should have failed", - response.getErrorCode(), BookieProtocol.EUA); - } - - // copy from TestAuth - BookieServer startAndStoreBookie(ServerConfiguration conf) throws Exception { - return startAndAddBookie(conf).getServer(); - } - - CompatClient42 newCompatClient(BookieId addr) throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - return new CompatClient42(conf, executor, eventLoopGroup, addr, authProvider, extRegistry); - } - - // extending PerChannelBookieClient to get the pipeline factory - class CompatClient42 extends PerChannelBookieClient { - final ArrayBlockingQueue responses = new ArrayBlockingQueue(10); - Channel channel; - final CountDownLatch connected = new CountDownLatch(1); - - CompatClient42(ClientConfiguration conf, - OrderedExecutor executor, - EventLoopGroup eventLoopGroup, - BookieId addr, - ClientAuthProvider.Factory authProviderFactory, - ExtensionRegistry extRegistry) throws Exception { - super(conf, - executor, - eventLoopGroup, - addr, - NullStatsLogger.INSTANCE, - authProviderFactory, - extRegistry, - null, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - state = ConnectionState.CONNECTING; - ChannelFuture future = connect(); - future.await(); - channel = future.channel(); - connected.countDown(); - } - - @Override - public void channelRead(io.netty.channel.ChannelHandlerContext ctx, Object msg) throws Exception { - if (!(msg instanceof Response)) { - LOG.error("Unknown message {}, passing upstream", msg); - ctx.fireChannelRead(msg); - return; - } - responses.add((Response) msg); - } - - Response takeResponse() throws Exception { - return responses.take(); - } - - Response pollResponse() throws Exception { - return responses.poll(); - } - - void sendRequest(Request request) throws Exception { - connected.await(); - channel.writeAndFlush(request); - } - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBookieRequestProcessor.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBookieRequestProcessor.java deleted file mode 100644 index 46304023433..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBookieRequestProcessor.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.protobuf.ByteString; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.group.ChannelGroup; -import io.netty.channel.group.DefaultChannelGroup; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.BookkeeperProtocol.AddRequest; -import org.apache.bookkeeper.proto.BookkeeperProtocol.AddRequest.Flag; -import org.apache.bookkeeper.proto.BookkeeperProtocol.BKPacketHeader; -import org.apache.bookkeeper.proto.BookkeeperProtocol.OperationType; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ProtocolVersion; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ReadRequest; -import org.apache.bookkeeper.proto.BookkeeperProtocol.Request; -import org.apache.bookkeeper.proto.BookkeeperProtocol.WriteLacRequest; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Test; - -/** - * Test utility methods from bookie request processor. - */ -public class TestBookieRequestProcessor { - - final BookieRequestProcessor requestProcessor = mock(BookieRequestProcessor.class); - - private final ChannelGroup channelGroup = new DefaultChannelGroup(null); - - @Test - public void testConstructLongPollThreads() throws Exception { - // long poll threads == read threads - ServerConfiguration conf = new ServerConfiguration(); - try (BookieRequestProcessor processor = new BookieRequestProcessor( - conf, mock(Bookie.class), NullStatsLogger.INSTANCE, null, UnpooledByteBufAllocator.DEFAULT, - channelGroup)) { - assertSame(processor.getReadThreadPool(), processor.getLongPollThreadPool()); - } - - // force create long poll threads if there is no read threads - conf = new ServerConfiguration(); - conf.setNumReadWorkerThreads(0); - try (BookieRequestProcessor processor = new BookieRequestProcessor( - conf, mock(Bookie.class), NullStatsLogger.INSTANCE, null, UnpooledByteBufAllocator.DEFAULT, - channelGroup)) { - assertNull(processor.getReadThreadPool()); - assertNotNull(processor.getLongPollThreadPool()); - } - - // long poll threads and no read threads - conf = new ServerConfiguration(); - conf.setNumReadWorkerThreads(2); - conf.setNumLongPollWorkerThreads(2); - try (BookieRequestProcessor processor = new BookieRequestProcessor( - conf, mock(Bookie.class), NullStatsLogger.INSTANCE, null, UnpooledByteBufAllocator.DEFAULT, - channelGroup)) { - assertNotNull(processor.getReadThreadPool()); - assertNotNull(processor.getLongPollThreadPool()); - assertNotSame(processor.getReadThreadPool(), processor.getLongPollThreadPool()); - } - } - - @Test - public void testFlagsV3() { - ReadRequest read = ReadRequest.newBuilder() - .setLedgerId(10).setEntryId(1) - .setFlag(ReadRequest.Flag.FENCE_LEDGER).build(); - assertTrue(RequestUtils.hasFlag(read, ReadRequest.Flag.FENCE_LEDGER)); - assertFalse(RequestUtils.hasFlag(read, ReadRequest.Flag.ENTRY_PIGGYBACK)); - - read = ReadRequest.newBuilder() - .setLedgerId(10).setEntryId(1) - .setFlag(ReadRequest.Flag.ENTRY_PIGGYBACK).build(); - assertFalse(RequestUtils.hasFlag(read, ReadRequest.Flag.FENCE_LEDGER)); - assertTrue(RequestUtils.hasFlag(read, ReadRequest.Flag.ENTRY_PIGGYBACK)); - - read = ReadRequest.newBuilder() - .setLedgerId(10).setEntryId(1) - .build(); - assertFalse(RequestUtils.hasFlag(read, ReadRequest.Flag.FENCE_LEDGER)); - assertFalse(RequestUtils.hasFlag(read, ReadRequest.Flag.ENTRY_PIGGYBACK)); - - AddRequest add = AddRequest.newBuilder() - .setLedgerId(10).setEntryId(1) - .setFlag(AddRequest.Flag.RECOVERY_ADD) - .setMasterKey(ByteString.EMPTY) - .setBody(ByteString.EMPTY) - .build(); - assertTrue(RequestUtils.hasFlag(add, AddRequest.Flag.RECOVERY_ADD)); - - add = AddRequest.newBuilder() - .setLedgerId(10).setEntryId(1) - .setMasterKey(ByteString.EMPTY) - .setBody(ByteString.EMPTY) - .build(); - assertFalse(RequestUtils.hasFlag(add, AddRequest.Flag.RECOVERY_ADD)); - - add = AddRequest.newBuilder() - .setLedgerId(10).setEntryId(1) - .setFlag(AddRequest.Flag.RECOVERY_ADD) - .setMasterKey(ByteString.EMPTY) - .setBody(ByteString.EMPTY) - .build(); - assertTrue(RequestUtils.hasFlag(add, AddRequest.Flag.RECOVERY_ADD)); - } - - @Test - public void testToString() { - BKPacketHeader.Builder headerBuilder = BKPacketHeader.newBuilder(); - headerBuilder.setVersion(ProtocolVersion.VERSION_THREE); - headerBuilder.setOperation(OperationType.ADD_ENTRY); - headerBuilder.setTxnId(5L); - BKPacketHeader header = headerBuilder.build(); - - AddRequest addRequest = AddRequest.newBuilder().setLedgerId(10).setEntryId(1) - .setMasterKey(ByteString.copyFrom("masterKey".getBytes())) - .setBody(ByteString.copyFrom("entrydata".getBytes())).build(); - Request request = Request.newBuilder().setHeader(header).setAddRequest(addRequest).build(); - - Channel channel = mock(Channel.class); - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - BookieRequestHandler requestHandler = mock(BookieRequestHandler.class); - when(requestHandler.ctx()).thenReturn(ctx); - - WriteEntryProcessorV3 writeEntryProcessorV3 = new WriteEntryProcessorV3(request, requestHandler, - requestProcessor); - String toString = writeEntryProcessorV3.toString(); - assertFalse("writeEntryProcessorV3's toString should have filtered out body", toString.contains("body")); - assertFalse("writeEntryProcessorV3's toString should have filtered out masterKey", - toString.contains("masterKey")); - assertTrue("writeEntryProcessorV3's toString should contain ledgerId", toString.contains("ledgerId")); - assertTrue("writeEntryProcessorV3's toString should contain entryId", toString.contains("entryId")); - assertTrue("writeEntryProcessorV3's toString should contain version", toString.contains("version")); - assertTrue("writeEntryProcessorV3's toString should contain operation", toString.contains("operation")); - assertTrue("writeEntryProcessorV3's toString should contain txnId", toString.contains("txnId")); - assertFalse("writeEntryProcessorV3's toString shouldn't contain flag", toString.contains("flag")); - assertFalse("writeEntryProcessorV3's toString shouldn't contain writeFlags", toString.contains("writeFlags")); - - addRequest = AddRequest.newBuilder().setLedgerId(10).setEntryId(1) - .setMasterKey(ByteString.copyFrom("masterKey".getBytes())) - .setBody(ByteString.copyFrom("entrydata".getBytes())).setFlag(Flag.RECOVERY_ADD).setWriteFlags(0) - .build(); - request = Request.newBuilder().setHeader(header).setAddRequest(addRequest).build(); - writeEntryProcessorV3 = new WriteEntryProcessorV3(request, requestHandler, requestProcessor); - toString = writeEntryProcessorV3.toString(); - assertFalse("writeEntryProcessorV3's toString should have filtered out body", toString.contains("body")); - assertFalse("writeEntryProcessorV3's toString should have filtered out masterKey", - toString.contains("masterKey")); - assertTrue("writeEntryProcessorV3's toString should contain flag", toString.contains("flag")); - assertTrue("writeEntryProcessorV3's toString should contain writeFlags", toString.contains("writeFlags")); - - ReadRequest readRequest = ReadRequest.newBuilder().setLedgerId(10).setEntryId(23) - .setMasterKey(ByteString.copyFrom("masterKey".getBytes())).build(); - request = Request.newBuilder().setHeader(header).setReadRequest(readRequest).build(); - toString = RequestUtils.toSafeString(request); - assertFalse("ReadRequest's safeString should have filtered out masterKey", toString.contains("masterKey")); - assertTrue("ReadRequest's safeString should contain ledgerId", toString.contains("ledgerId")); - assertTrue("ReadRequest's safeString should contain entryId", toString.contains("entryId")); - assertTrue("ReadRequest's safeString should contain version", toString.contains("version")); - assertTrue("ReadRequest's safeString should contain operation", toString.contains("operation")); - assertTrue("ReadRequest's safeString should contain txnId", toString.contains("txnId")); - assertFalse("ReadRequest's safeString shouldn't contain flag", toString.contains("flag")); - assertFalse("ReadRequest's safeString shouldn't contain previousLAC", toString.contains("previousLAC")); - assertFalse("ReadRequest's safeString shouldn't contain timeOut", toString.contains("timeOut")); - - readRequest = ReadRequest.newBuilder().setLedgerId(10).setEntryId(23).setPreviousLAC(2).setTimeOut(100) - .setMasterKey(ByteString.copyFrom("masterKey".getBytes())).setFlag(ReadRequest.Flag.ENTRY_PIGGYBACK) - .build(); - request = Request.newBuilder().setHeader(header).setReadRequest(readRequest).build(); - toString = RequestUtils.toSafeString(request); - assertFalse("ReadRequest's safeString should have filtered out masterKey", toString.contains("masterKey")); - assertTrue("ReadRequest's safeString shouldn contain flag", toString.contains("flag")); - assertTrue("ReadRequest's safeString shouldn contain previousLAC", toString.contains("previousLAC")); - assertTrue("ReadRequest's safeString shouldn contain timeOut", toString.contains("timeOut")); - - WriteLacRequest writeLacRequest = WriteLacRequest.newBuilder().setLedgerId(10).setLac(23) - .setMasterKey(ByteString.copyFrom("masterKey".getBytes())) - .setBody(ByteString.copyFrom("entrydata".getBytes())).build(); - request = Request.newBuilder().setHeader(header).setWriteLacRequest(writeLacRequest).build(); - WriteLacProcessorV3 writeLacProcessorV3 = new WriteLacProcessorV3(request, null, requestProcessor); - toString = writeLacProcessorV3.toString(); - assertFalse("writeLacProcessorV3's toString should have filtered out body", toString.contains("body")); - assertFalse("writeLacProcessorV3's toString should have filtered out masterKey", - toString.contains("masterKey")); - assertTrue("writeLacProcessorV3's toString should contain ledgerId", toString.contains("ledgerId")); - assertTrue("writeLacProcessorV3's toString should contain lac", toString.contains("lac")); - assertTrue("writeLacProcessorV3's toString should contain version", toString.contains("version")); - assertTrue("writeLacProcessorV3's toString should contain operation", toString.contains("operation")); - assertTrue("writeLacProcessorV3's toString should contain txnId", toString.contains("txnId")); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClient.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClient.java deleted file mode 100644 index b52e8b95db7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClient.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.protobuf.ExtensionRegistry; -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.epoll.Epoll; -import io.netty.channel.epoll.EpollChannelOption; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.auth.AuthProviderFactoryFactory; -import org.apache.bookkeeper.auth.ClientAuthProvider; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback; -import org.apache.bookkeeper.proto.PerChannelBookieClient.ConnectionState; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Assume; -import org.junit.Test; -import org.mockito.Mockito; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests for PerChannelBookieClient. Historically, this class has - * had a few race conditions, so this is what these tests focus on. - */ -public class TestPerChannelBookieClient extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(TestPerChannelBookieClient.class); - - ExtensionRegistry extRegistry = ExtensionRegistry.newInstance(); - ClientAuthProvider.Factory authProvider; - - public TestPerChannelBookieClient() throws Exception { - super(1); - authProvider = AuthProviderFactoryFactory.newClientAuthProviderFactory( - new ClientConfiguration()); - } - - - /** - * Test that a race does not exist between connection completion - * and client closure. If a race does exist, this test will simply - * hang at releaseExternalResources() as it is uninterruptible. - * This specific race was found in - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-485}. - */ - @Test - public void testConnectCloseRace() throws Exception { - EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); - OrderedExecutor executor = getOrderedSafeExecutor(); - - BookieId addr = getBookie(0); - for (int i = 0; i < 1000; i++) { - PerChannelBookieClient client = new PerChannelBookieClient(executor, eventLoopGroup, addr, - authProvider, extRegistry, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - client.connectIfNeededAndDoOp(new GenericCallback() { - @Override - public void operationComplete(int rc, PerChannelBookieClient client) { - // do nothing, we don't care about doing anything with the connection, - // we just want to trigger it connecting. - } - }); - client.close(); - } - eventLoopGroup.shutdownGracefully(); - executor.shutdown(); - } - - public OrderedExecutor getOrderedSafeExecutor() { - return OrderedExecutor.newBuilder() - .name("PCBC") - .numThreads(1) - .traceTaskExecution(true) - .traceTaskWarnTimeMicroSec(TimeUnit.MILLISECONDS.toMicros(100)) - .build(); - } - - /** - * Test race scenario found in {@link https://issues.apache.org/jira/browse/BOOKKEEPER-5} - * where multiple clients try to connect a channel simultaneously. If not synchronised - * correctly, this causes the netty channel to get orphaned. - */ - @Test - public void testConnectRace() throws Exception { - GenericCallback nullop = new GenericCallback() { - @Override - public void operationComplete(int rc, PerChannelBookieClient pcbc) { - // do nothing, we don't care about doing anything with the connection, - // we just want to trigger it connecting. - } - }; - EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); - OrderedExecutor executor = getOrderedSafeExecutor(); - - BookieId addr = getBookie(0); - for (int i = 0; i < 100; i++) { - PerChannelBookieClient client = new PerChannelBookieClient(executor, eventLoopGroup, addr, - authProvider, extRegistry, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - for (int j = i; j < 10; j++) { - client.connectIfNeededAndDoOp(nullop); - } - client.close(); - } - eventLoopGroup.shutdownGracefully(); - executor.shutdown(); - } - - /** - * Test that all resources are freed if connections and disconnections - * are interleaved randomly. - * - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-620} - */ - @Test - public void testDisconnectRace() throws Exception { - final GenericCallback nullop = new GenericCallback() { - @Override - public void operationComplete(int rc, PerChannelBookieClient client) { - // do nothing, we don't care about doing anything with the connection, - // we just want to trigger it connecting. - } - }; - final int iterations = 100000; - EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); - OrderedExecutor executor = getOrderedSafeExecutor(); - BookieId addr = getBookie(0); - - final PerChannelBookieClient client = new PerChannelBookieClient(executor, eventLoopGroup, - addr, authProvider, extRegistry, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - final AtomicBoolean shouldFail = new AtomicBoolean(false); - final AtomicBoolean running = new AtomicBoolean(true); - final CountDownLatch disconnectRunning = new CountDownLatch(1); - Thread connectThread = new Thread() { - public void run() { - try { - if (!disconnectRunning.await(10, TimeUnit.SECONDS)) { - LOG.error("Disconnect thread never started"); - shouldFail.set(true); - } - } catch (InterruptedException ie) { - LOG.error("Connect thread interrupted", ie); - Thread.currentThread().interrupt(); - running.set(false); - } - for (int i = 0; i < iterations && running.get(); i++) { - client.connectIfNeededAndDoOp(nullop); - } - running.set(false); - } - }; - Thread disconnectThread = new Thread() { - public void run() { - disconnectRunning.countDown(); - while (running.get()) { - client.disconnect(); - } - } - }; - Thread checkThread = new Thread() { - public void run() { - ConnectionState state; - Channel channel; - while (running.get()) { - synchronized (client) { - state = client.state; - channel = client.channel; - - if ((state == ConnectionState.CONNECTED - && (channel == null - || !channel.isActive())) - || (state != ConnectionState.CONNECTED - && channel != null - && channel.isActive())) { - LOG.error("State({}) and channel({}) inconsistent " + channel, - state, channel == null ? null : channel.isActive()); - shouldFail.set(true); - running.set(false); - } - } - } - } - }; - connectThread.start(); - disconnectThread.start(); - checkThread.start(); - - connectThread.join(); - disconnectThread.join(); - checkThread.join(); - assertFalse("Failure in threads, check logs", shouldFail.get()); - client.close(); - eventLoopGroup.shutdownGracefully(); - executor.shutdown(); - } - - /** - * Test that requests are completed even if the channel is disconnected - * {@link https://issues.apache.org/jira/browse/BOOKKEEPER-668}. - */ - @Test - public void testRequestCompletesAfterDisconnectRace() throws Exception { - ServerConfiguration conf = killBookie(0); - - Bookie delayBookie = new TestBookieImpl(conf) { - @Override - public ByteBuf readEntry(long ledgerId, long entryId) - throws IOException, NoLedgerException, BookieException { - try { - Thread.sleep(3000); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw new IOException("Interrupted waiting", ie); - } - return super.readEntry(ledgerId, entryId); - } - }; - startAndAddBookie(conf, delayBookie); - - EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); - final OrderedExecutor executor = getOrderedSafeExecutor(); - BookieId addr = getBookie(0); - - final PerChannelBookieClient client = new PerChannelBookieClient(executor, eventLoopGroup, - addr, authProvider, extRegistry, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - final CountDownLatch completion = new CountDownLatch(1); - final ReadEntryCallback cb = new ReadEntryCallback() { - @Override - public void readEntryComplete(int rc, long ledgerId, long entryId, - ByteBuf buffer, Object ctx) { - completion.countDown(); - } - }; - - client.connectIfNeededAndDoOp(new GenericCallback() { - @Override - public void operationComplete(final int rc, PerChannelBookieClient pcbc) { - if (rc != BKException.Code.OK) { - executor.executeOrdered(1, () -> cb.readEntryComplete(rc, 1, 1, null, null)); - return; - } - - client.readEntry(1, 1, cb, null, BookieProtocol.FLAG_DO_FENCING, - "00000111112222233333".getBytes(), false); - } - }); - - Thread.sleep(1000); - client.disconnect(); - client.close(); - - assertTrue("Request should have completed", completion.await(5, TimeUnit.SECONDS)); - - eventLoopGroup.shutdownGracefully(); - executor.shutdown(); - } - - /** - * Test that TCP user timeout is correctly set in EpollEventLoopGroup. - */ - @Test - public void testEpollChannelTcpUserTimeout() throws Exception { - // Epoll is needed for this test to work. - Assume.assumeTrue(Epoll.isAvailable()); - - EventLoopGroup eventLoopGroup = new EpollEventLoopGroup(); - OrderedExecutor executor = getOrderedSafeExecutor(); - ClientConfiguration conf = new ClientConfiguration(); - int tcpUserTimeout = 1236; // this value may be rounded on some Linux implementations - BookieId addr = getBookie(0); - - // Pass to the PerChannelBookieClient object the client configuration with TCP user timeout. - PerChannelBookieClient channel = new PerChannelBookieClient(conf, executor, eventLoopGroup, - addr, Mockito.mock(StatsLogger.class), authProvider, extRegistry, - Mockito.mock(PerChannelBookieClientPool.class), BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Verify that the configured value has not been set in the channel if does not exist in config. - assertEquals(channel.connect().channel().config() - .getOption(EpollChannelOption.TCP_USER_TIMEOUT).intValue(), 0); - channel.close(); - - // Create a new channel with new TCP user timeout set. - conf.setTcpUserTimeoutMillis(tcpUserTimeout); - channel = new PerChannelBookieClient(conf, executor, eventLoopGroup, - addr, Mockito.mock(StatsLogger.class), authProvider, extRegistry, - Mockito.mock(PerChannelBookieClientPool.class), BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - // Verify that the configured value has been set. - assertEquals(channel.connect().channel().config() - .getOption(EpollChannelOption.TCP_USER_TIMEOUT).intValue(), tcpUserTimeout); - channel.close(); - eventLoopGroup.shutdownGracefully(); - executor.shutdown(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorTest.java deleted file mode 100644 index a02cde4ab99..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorTest.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.channel.DefaultChannelPromise; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.proto.BookieProtocol.ParsedAddRequest; -import org.apache.bookkeeper.proto.BookieProtocol.Response; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link WriteEntryProcessor}. - */ -public class WriteEntryProcessorTest { - - private ParsedAddRequest request; - private WriteEntryProcessor processor; - private Channel channel; - private ChannelHandlerContext ctx; - private BookieRequestHandler requestHandler; - private BookieRequestProcessor requestProcessor; - private Bookie bookie; - - @Before - public void setup() { - request = ParsedAddRequest.create( - BookieProtocol.CURRENT_PROTOCOL_VERSION, - System.currentTimeMillis(), - System.currentTimeMillis() + 1, - (short) 0, - new byte[0], - Unpooled.wrappedBuffer("test-entry-data".getBytes(UTF_8))); - channel = mock(Channel.class); - when(channel.isOpen()).thenReturn(true); - - requestHandler = mock(BookieRequestHandler.class); - ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - when(requestHandler.ctx()).thenReturn(ctx); - - bookie = mock(Bookie.class); - requestProcessor = mock(BookieRequestProcessor.class); - when(requestProcessor.getBookie()).thenReturn(bookie); - when(requestProcessor.getRequestStats()).thenReturn(new RequestStats(NullStatsLogger.INSTANCE)); - when(channel.isActive()).thenReturn(true); - when(channel.isWritable()).thenReturn(true); - processor = WriteEntryProcessor.create( - request, - requestHandler, - requestProcessor); - } - - private void reinitRequest(short flags) { - request.release(); - request.recycle(); - processor.recycle(); - - request = ParsedAddRequest.create( - BookieProtocol.CURRENT_PROTOCOL_VERSION, - System.currentTimeMillis(), - System.currentTimeMillis() + 1, - flags, - new byte[0], - Unpooled.wrappedBuffer("test-entry-data".getBytes(UTF_8))); - processor = WriteEntryProcessor.create( - request, - requestHandler, - requestProcessor); - } - - @Test - public void testNoneHighPriorityWritesOnReadOnlyBookie() throws Exception { - when(bookie.isReadOnly()).thenReturn(true); - ChannelPromise mockPromise = mock(ChannelPromise.class); - when(channel.newPromise()).thenReturn(mockPromise); - when(mockPromise.addListener(any())).thenReturn(mockPromise); - - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return null; - }).when(channel).writeAndFlush(any(), any()); - - processor.run(); - - verify(channel, times(1)).writeAndFlush(any(), any()); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(BookieProtocol.EREADONLY, response.getErrorCode()); - - response.release(); - response.recycle(); - } - - @Test - public void testHighPriorityWritesOnReadOnlyBookieWhenHighPriorityWritesDisallowed() throws Exception { - reinitRequest(BookieProtocol.FLAG_HIGH_PRIORITY); - - when(bookie.isReadOnly()).thenReturn(true); - when(bookie.isAvailableForHighPriorityWrites()).thenReturn(false); - ChannelPromise mockPromise = mock(ChannelPromise.class); - when(channel.newPromise()).thenReturn(mockPromise); - when(mockPromise.addListener(any())).thenReturn(mockPromise); - - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return null; - }).when(channel).writeAndFlush(any(), any()); - - processor.run(); - - verify(channel, times(1)).writeAndFlush(any(), any()); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(BookieProtocol.EREADONLY, response.getErrorCode()); - - response.release(); - response.recycle(); - } - - @Test - public void testHighPriorityWritesOnReadOnlyBookieWhenHighPriorityWritesAllowed() throws Exception { - reinitRequest(BookieProtocol.FLAG_HIGH_PRIORITY); - - when(bookie.isReadOnly()).thenReturn(true); - when(bookie.isAvailableForHighPriorityWrites()).thenReturn(true); - ChannelPromise mockPromise = mock(ChannelPromise.class); - when(channel.newPromise()).thenReturn(mockPromise); - when(mockPromise.addListener(any())).thenReturn(mockPromise); - doAnswer(invocationOnMock -> { - processor.writeComplete(0, request.ledgerId, request.entryId, null, null); - return null; - }).when(bookie).addEntry(any(ByteBuf.class), eq(false), same(processor), same(requestHandler), eq(new byte[0])); - - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return null; - }).when(requestHandler).prepareSendResponseV2(anyInt(), any()); - - processor.run(); - - verify(bookie, times(1)) - .addEntry(any(ByteBuf.class), eq(false), same(processor), same(requestHandler), eq(new byte[0])); - verify(requestHandler, times(1)).prepareSendResponseV2(anyInt(), any()); -// verify(channel, times(1)).writeAndFlush(any(), any()); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Integer); - assertEquals(BookieProtocol.EOK, (int) writtenObject.get()); - } - - @Test - public void testNormalWritesOnWritableBookie() throws Exception { - when(bookie.isReadOnly()).thenReturn(false); - ChannelPromise mockPromise = mock(ChannelPromise.class); - when(channel.newPromise()).thenReturn(mockPromise); - when(mockPromise.addListener(any())).thenReturn(mockPromise); - doAnswer(invocationOnMock -> { - processor.writeComplete(0, request.ledgerId, request.entryId, null, null); - return null; - }).when(bookie).addEntry(any(ByteBuf.class), eq(false), same(processor), same(requestHandler), eq(new byte[0])); - - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return null; - }).when(requestHandler).prepareSendResponseV2(anyInt(), any()); - - processor.run(); - - verify(bookie, times(1)) - .addEntry(any(ByteBuf.class), eq(false), same(processor), same(requestHandler), eq(new byte[0])); - verify(requestHandler, times(1)).prepareSendResponseV2(anyInt(), any()); - - latch.await(); - - assertEquals(BookieProtocol.EOK, (int) writtenObject.get()); - } - - @Test - public void testWritesCacheFlushTimeout() throws Exception { - when(bookie.isReadOnly()).thenReturn(false); - ChannelPromise mockPromise = mock(ChannelPromise.class); - when(channel.newPromise()).thenReturn(mockPromise); - when(mockPromise.addListener(any())).thenReturn(mockPromise); - when(channel.writeAndFlush(any())).thenReturn(mock(ChannelPromise.class)); - doAnswer(invocationOnMock -> { - throw new BookieException.OperationRejectedException(); - }).when(bookie).addEntry( - any(ByteBuf.class), eq(false), same(processor), same(requestHandler), eq(new byte[0])); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any(), any()); - - processor.run(); - - verify(bookie, times(1)) - .addEntry(any(ByteBuf.class), eq(false), same(processor), same(requestHandler), eq(new byte[0])); - verify(channel, times(1)).writeAndFlush(any(Response.class), any()); - - latch.await(); - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(BookieProtocol.ETOOMANYREQUESTS, response.getErrorCode()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorV3Test.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorV3Test.java deleted file mode 100644 index 40eb662cc54..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorV3Test.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.proto; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.protobuf.ByteString; -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.channel.DefaultChannelPromise; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.proto.BookkeeperProtocol.AddRequest; -import org.apache.bookkeeper.proto.BookkeeperProtocol.BKPacketHeader; -import org.apache.bookkeeper.proto.BookkeeperProtocol.OperationType; -import org.apache.bookkeeper.proto.BookkeeperProtocol.ProtocolVersion; -import org.apache.bookkeeper.proto.BookkeeperProtocol.Request; -import org.apache.bookkeeper.proto.BookkeeperProtocol.Response; -import org.apache.bookkeeper.proto.BookkeeperProtocol.StatusCode; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link WriteEntryProcessor}. - */ -public class WriteEntryProcessorV3Test { - - private Request request; - private WriteEntryProcessorV3 processor; - - private Channel channel; - private BookieRequestHandler requestHandler; - private BookieRequestProcessor requestProcessor; - private Bookie bookie; - - @Before - public void setup() { - request = Request.newBuilder() - .setHeader(BKPacketHeader.newBuilder() - .setTxnId(System.currentTimeMillis()) - .setVersion(ProtocolVersion.VERSION_THREE) - .setOperation(OperationType.ADD_ENTRY) - .build()) - .setAddRequest(AddRequest.newBuilder() - .setLedgerId(System.currentTimeMillis()) - .setEntryId(System.currentTimeMillis() + 1) - .setBody(ByteString.copyFromUtf8("test-entry-data")) - .setMasterKey(ByteString.copyFrom(new byte[0])) - .build()) - .build(); - channel = mock(Channel.class); - when(channel.isOpen()).thenReturn(true); - - requestHandler = mock(BookieRequestHandler.class); - ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - when(requestHandler.ctx()).thenReturn(ctx); - - bookie = mock(Bookie.class); - requestProcessor = mock(BookieRequestProcessor.class); - when(requestProcessor.getBookie()).thenReturn(bookie); - when(requestProcessor.getWaitTimeoutOnBackpressureMillis()).thenReturn(-1L); - when(requestProcessor.getRequestStats()).thenReturn(new RequestStats(NullStatsLogger.INSTANCE)); - when(channel.isActive()).thenReturn(true); - processor = new WriteEntryProcessorV3( - request, - requestHandler, - requestProcessor); - } - - private void reinitRequest(int priority) { - request = Request.newBuilder(request) - .setHeader(BKPacketHeader.newBuilder(request.getHeader()) - .setPriority(priority) - .build()) - .build(); - - processor = new WriteEntryProcessorV3( - request, - requestHandler, - requestProcessor); - } - - @Test - public void testNoneHighPriorityWritesOnReadOnlyBookie() throws Exception { - when(bookie.isReadOnly()).thenReturn(true); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any()); - - processor.run(); - - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(StatusCode.EREADONLY, response.getStatus()); - } - - @Test - public void testHighPriorityWritesOnReadOnlyBookieWhenHighPriorityWritesDisallowed() throws Exception { - reinitRequest(100); - - when(bookie.isReadOnly()).thenReturn(true); - when(bookie.isAvailableForHighPriorityWrites()).thenReturn(false); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any()); - - processor.run(); - - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(StatusCode.EREADONLY, response.getStatus()); - } - - @Test - public void testHighPriorityWritesOnReadOnlyBookieWhenHighPriorityWritesAllowed() throws Exception { - reinitRequest(BookieProtocol.FLAG_HIGH_PRIORITY); - - when(bookie.isReadOnly()).thenReturn(true); - when(bookie.isAvailableForHighPriorityWrites()).thenReturn(true); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - - doAnswer(invocationOnMock -> { - WriteCallback wc = invocationOnMock.getArgument(2); - - wc.writeComplete( - 0, - request.getAddRequest().getLedgerId(), - request.getAddRequest().getEntryId(), - null, - null); - return null; - }).when(bookie).addEntry( - any(ByteBuf.class), - eq(false), - any(WriteCallback.class), - same(channel), - eq(new byte[0])); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any()); - - processor.run(); - - verify(bookie, times(1)) - .addEntry(any(ByteBuf.class), eq(false), any(WriteCallback.class), same(channel), eq(new byte[0])); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(StatusCode.EOK, response.getStatus()); - } - - @Test - public void testNormalWritesOnWritableBookie() throws Exception { - when(bookie.isReadOnly()).thenReturn(false); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - when(channel.writeAndFlush(any())).thenReturn(mock(ChannelPromise.class)); - doAnswer(invocationOnMock -> { - WriteCallback wc = invocationOnMock.getArgument(2); - - wc.writeComplete( - 0, - request.getAddRequest().getLedgerId(), - request.getAddRequest().getEntryId(), - null, - null); - return null; - }).when(bookie).addEntry( - any(ByteBuf.class), eq(false), any(WriteCallback.class), same(channel), eq(new byte[0])); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any()); - - processor.run(); - - verify(bookie, times(1)) - .addEntry(any(ByteBuf.class), eq(false), any(WriteCallback.class), same(channel), eq(new byte[0])); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - latch.await(); - - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(StatusCode.EOK, response.getStatus()); - } - - @Test - public void testWritesCacheFlushTimeout() throws Exception { - when(bookie.isReadOnly()).thenReturn(false); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - when(channel.writeAndFlush(any())).thenReturn(mock(ChannelPromise.class)); - doAnswer(invocationOnMock -> { - throw new BookieException.OperationRejectedException(); - }).when(bookie).addEntry( - any(ByteBuf.class), eq(false), any(WriteCallback.class), same(channel), eq(new byte[0])); - - ChannelPromise promise = new DefaultChannelPromise(channel); - AtomicReference writtenObject = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - doAnswer(invocationOnMock -> { - writtenObject.set(invocationOnMock.getArgument(0)); - latch.countDown(); - return promise; - }).when(channel).writeAndFlush(any()); - - processor.run(); - - verify(bookie, times(1)) - .addEntry(any(ByteBuf.class), eq(false), any(WriteCallback.class), same(channel), eq(new byte[0])); - verify(channel, times(1)).writeAndFlush(any(Response.class)); - - latch.await(); - assertTrue(writtenObject.get() instanceof Response); - Response response = (Response) writtenObject.get(); - assertEquals(StatusCode.ETOOMANYREQUESTS, response.getStatus()); - } - - @Test - public void testWritesWithClientNotAcceptingReponses() throws Exception { - when(requestProcessor.getWaitTimeoutOnBackpressureMillis()).thenReturn(5L); - - doAnswer(invocationOnMock -> { - Channel ch = invocationOnMock.getArgument(0); - ch.close(); - return null; - }).when(requestProcessor).handleNonWritableChannel(any()); - - when(channel.isWritable()).thenReturn(false); - - when(bookie.isReadOnly()).thenReturn(false); - when(channel.voidPromise()).thenReturn(mock(ChannelPromise.class)); - when(channel.writeAndFlush(any())).thenReturn(mock(ChannelPromise.class)); - doAnswer(invocationOnMock -> { - WriteCallback wc = invocationOnMock.getArgument(2); - - wc.writeComplete( - 0, - request.getAddRequest().getLedgerId(), - request.getAddRequest().getEntryId(), - null, - null); - return null; - }).when(bookie).addEntry( - any(ByteBuf.class), eq(false), any(WriteCallback.class), same(channel), eq(new byte[0])); - - processor.run(); - - verify(bookie, times(1)) - .addEntry(any(ByteBuf.class), eq(false), any(WriteCallback.class), same(channel), eq(new byte[0])); - verify(requestProcessor, times(1)).handleNonWritableChannel(channel); - verify(channel, times(0)).writeAndFlush(any(Response.class)); - verify(channel, times(1)).close(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/checksum/CompositeByteBufUnwrapBugReproduceTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/checksum/CompositeByteBufUnwrapBugReproduceTest.java deleted file mode 100644 index 6252bb71be9..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/checksum/CompositeByteBufUnwrapBugReproduceTest.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.proto.checksum; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; - -import com.scurrilous.circe.checksum.IntHash; -import com.scurrilous.circe.checksum.Java8IntHash; -import com.scurrilous.circe.checksum.Java9IntHash; -import com.scurrilous.circe.checksum.JniIntHash; -import com.scurrilous.circe.crc.Sse42Crc32C; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.CompositeByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCounted; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import org.apache.bookkeeper.proto.BookieProtoEncoding; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.util.ByteBufList; -import org.apache.bookkeeper.util.ByteBufVisitor; -import org.apache.commons.lang3.RandomUtils; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -/** - * This test class was added to reproduce a bug in the checksum calculation when - * the payload is a CompositeByteBuf and this buffer has a reader index state other than 0. - * The reader index state gets lost in the unwrapping process. - * - * There were at least 2 different bugs. One that occured when the - * payload was >= BookieProtoEncoding.SMALL_ENTRY_SIZE_THRESHOLD and the other when - * it was < BookieProtoEncoding.SMALL_ENTRY_SIZE_THRESHOLD. - * This test covers both useV2Protocol=true and useV2Protocol=false since the bug was triggered differently. - * - * The bug has been fixed and this test is here to make sure it doesn't happen again. - */ -@RunWith(Parameterized.class) -public class CompositeByteBufUnwrapBugReproduceTest { - final byte[] testPayLoad; - final int defaultBufferPrefixLength; - private final boolean useV2Protocol; - - // set to 0 to 3 to run a single scenario for debugging purposes - private static final int RUN_SINGLE_SCENARIO_FOR_DEBUGGING = -1; - - @Parameterized.Parameters - public static Collection testScenarios() { - List scenarios = Arrays.asList(new Object[][] { - {BookieProtoEncoding.SMALL_ENTRY_SIZE_THRESHOLD - 1, true}, - {BookieProtoEncoding.SMALL_ENTRY_SIZE_THRESHOLD - 1, false}, - {BookieProtoEncoding.SMALL_ENTRY_SIZE_THRESHOLD, true}, - {BookieProtoEncoding.SMALL_ENTRY_SIZE_THRESHOLD, false} - }); - if (RUN_SINGLE_SCENARIO_FOR_DEBUGGING >= 0) { - // pick a single scenario for debugging - scenarios = scenarios.subList(RUN_SINGLE_SCENARIO_FOR_DEBUGGING, 1); - } - return scenarios; - } - - public CompositeByteBufUnwrapBugReproduceTest(int payloadSize, boolean useV2Protocol) { - this.testPayLoad = createTestPayLoad(payloadSize); - this.defaultBufferPrefixLength = payloadSize / 7; - this.useV2Protocol = useV2Protocol; - } - - private static byte[] createTestPayLoad(int payloadSize) { - byte[] payload = new byte[payloadSize]; - for (int i = 0; i < payloadSize; i++) { - payload[i] = (byte) i; - } - return payload; - } - - - /** - * A DigestManager that uses the given IntHash implementation for testing. - */ - static class TestIntHashDigestManager extends DigestManager { - private final IntHash intHash; - - public TestIntHashDigestManager(IntHash intHash, long ledgerId, boolean useV2Protocol, - ByteBufAllocator allocator) { - super(ledgerId, useV2Protocol, allocator); - this.intHash = intHash; - } - - @Override - int getMacCodeLength() { - return 4; - } - - @Override - boolean isInt32Digest() { - return true; - } - - @Override - void populateValueAndReset(int digest, ByteBuf buf) { - buf.writeInt(digest); - } - - @Override - int internalUpdate(int digest, ByteBuf data, int offset, int len) { - return intHash.resume(digest, data, offset, len); - } - - @Override - int internalUpdate(int digest, byte[] buffer, int offset, int len) { - return intHash.resume(digest, buffer, offset, len); - } - - @Override - boolean acceptsMemoryAddressBuffer() { - return intHash.acceptsMemoryAddressBuffer(); - } - } - - @Test - public void shouldCalculateChecksumForCompositeBuffer() { - ByteBuf testPayload = Unpooled.wrappedBuffer(testPayLoad); - byte[] referenceOutput = computeDigestAndPackageForSending(new Java8IntHash(), testPayload.retainedDuplicate()); - assertDigestAndPackageMatchesReference(new Java8IntHash(), testPayload, referenceOutput); - assertDigestAndPackageMatchesReference(new Java9IntHash(), testPayload, referenceOutput); - if (Sse42Crc32C.isSupported()) { - assertDigestAndPackageMatchesReference(new JniIntHash(), testPayload, referenceOutput); - } - testPayload.release(); - } - - private void assertDigestAndPackageMatchesReference(IntHash intHash, ByteBuf payload, byte[] referenceOutput) { - assertDigestAndPackageScenario(intHash, payload.retainedDuplicate(), referenceOutput, testPayLoad, - "plain payload, no wrapping"); - - ByteBuf payload2 = wrapWithPrefixAndCompositeByteBufWithReaderIndexState(payload.retainedDuplicate(), - defaultBufferPrefixLength); - assertDigestAndPackageScenario(intHash, payload2, referenceOutput, testPayLoad, - "payload with prefix wrapped in CompositeByteBuf with readerIndex state"); - - ByteBuf payload3 = wrapWithPrefixAndMultipleCompositeByteBufWithReaderIndexStateAndMultipleLayersOfDuplicate( - payload.retainedDuplicate(), defaultBufferPrefixLength); - assertDigestAndPackageScenario(intHash, payload3, referenceOutput, testPayLoad, - "payload with prefix wrapped in 2 layers of CompositeByteBuf with readerIndex state in the outer " - + "composite. In addition, the outer composite is duplicated twice."); - - ByteBuf payload4 = wrapInCompositeByteBufAndSlice(payload.retainedDuplicate(), defaultBufferPrefixLength); - assertDigestAndPackageScenario(intHash, payload4, referenceOutput, testPayLoad, - "payload with prefix wrapped in CompositeByteBuf and sliced"); - } - - private void assertDigestAndPackageScenario(IntHash intHash, ByteBuf payload, byte[] referenceOutput, - byte[] testPayLoadArray, - String scenario) { - // this validates that the readable bytes in the payload match the TEST_PAYLOAD content - assertArrayEquals(testPayLoadArray, ByteBufUtil.getBytes(payload.duplicate()), - "input is invalid for scenario '" + scenario + "'"); - - ByteBuf visitedCopy = Unpooled.buffer(payload.readableBytes()); - ByteBufVisitor.visitBuffers(payload, payload.readerIndex(), payload.readableBytes(), - new ByteBufVisitor.ByteBufVisitorCallback() { - @Override - public void visitBuffer(Void context, ByteBuf visitBuffer, int visitIndex, int visitLength) { - visitedCopy.writeBytes(visitBuffer, visitIndex, visitLength); - } - - @Override - public void visitArray(Void context, byte[] visitArray, int visitIndex, int visitLength) { - visitedCopy.writeBytes(visitArray, visitIndex, visitLength); - } - }, null); - - assertArrayEquals(ByteBufUtil.getBytes(visitedCopy), testPayLoadArray, - "visited copy is invalid for scenario '" + scenario + "'. Bug in ByteBufVisitor?"); - - // compute the digest and package - byte[] output = computeDigestAndPackageForSending(intHash, payload.duplicate()); - if (referenceOutput == null) { - referenceOutput = - computeDigestAndPackageForSending(new Java8IntHash(), Unpooled.wrappedBuffer(testPayLoadArray)); - } - // this validates that the output matches the reference output - assertArrayEquals(referenceOutput, output, "output is invalid for scenario '" + scenario + "'"); - } - - private byte[] computeDigestAndPackageForSending(IntHash intHash, ByteBuf data) { - DigestManager digestManager = new TestIntHashDigestManager(intHash, 1, useV2Protocol, ByteBufAllocator.DEFAULT); - ReferenceCounted packagedBuffer = - digestManager.computeDigestAndPackageForSending(1, 0, data.readableBytes(), data, - MacDigestManager.EMPTY_LEDGER_KEY, BookieProtocol.FLAG_NONE); - return packagedBufferToBytes(packagedBuffer); - } - - ByteBuf wrapWithPrefixAndCompositeByteBufWithReaderIndexState(ByteBuf payload, int bufferPrefixLength) { - // create a new buffer with a prefix and the actual payload - ByteBuf prefixedPayload = ByteBufAllocator.DEFAULT.buffer(bufferPrefixLength + payload.readableBytes()); - prefixedPayload.writeBytes(RandomUtils.nextBytes(bufferPrefixLength)); - prefixedPayload.writeBytes(payload); - - // wrap the buffer in a composite buffer - CompositeByteBuf outerComposite = ByteBufAllocator.DEFAULT.compositeBuffer(); - outerComposite.addComponent(true, prefixedPayload); - - // set reader index state. this is the state that gets lost in the unwrapping process - outerComposite.readerIndex(bufferPrefixLength); - - return outerComposite; - } - - ByteBuf wrapWithPrefixAndMultipleCompositeByteBufWithReaderIndexStateAndMultipleLayersOfDuplicate(ByteBuf payload, - int bufferPrefixLength) { - // create a new buffer with a prefix and the actual payload - ByteBuf prefixedPayload = ByteBufAllocator.DEFAULT.buffer(bufferPrefixLength + payload.readableBytes()); - prefixedPayload.writeBytes(RandomUtils.nextBytes(bufferPrefixLength)); - prefixedPayload.writeBytes(payload); - - CompositeByteBuf innerComposite = ByteBufAllocator.DEFAULT.compositeBuffer(); - innerComposite.addComponent(true, prefixedPayload); - innerComposite.addComponent(true, Unpooled.EMPTY_BUFFER); - - // wrap the buffer in a composite buffer - CompositeByteBuf outerComposite = ByteBufAllocator.DEFAULT.compositeBuffer(); - outerComposite.addComponent(true, innerComposite); - outerComposite.addComponent(true, Unpooled.EMPTY_BUFFER); - - // set reader index state. this is the state that gets lost in the unwrapping process - outerComposite.readerIndex(bufferPrefixLength); - - return outerComposite.duplicate().duplicate(); - } - - ByteBuf wrapInCompositeByteBufAndSlice(ByteBuf payload, int bufferPrefixLength) { - // create a composite buffer - CompositeByteBuf compositeWithPrefix = ByteBufAllocator.DEFAULT.compositeBuffer(); - compositeWithPrefix.addComponent(true, Unpooled.wrappedBuffer(RandomUtils.nextBytes(bufferPrefixLength))); - compositeWithPrefix.addComponent(true, payload); - - // return a slice of the composite buffer so that it returns the payload - return compositeWithPrefix.slice(bufferPrefixLength, payload.readableBytes()); - } - - private static byte[] packagedBufferToBytes(ReferenceCounted packagedBuffer) { - byte[] output; - if (packagedBuffer instanceof ByteBufList) { - ByteBufList bufList = (ByteBufList) packagedBuffer; - output = new byte[bufList.readableBytes()]; - bufList.getBytes(output); - for (int i = 0; i < bufList.size(); i++) { - bufList.getBuffer(i).release(); - } - } else if (packagedBuffer instanceof ByteBuf) { - output = ByteBufUtil.getBytes((ByteBuf) packagedBuffer); - packagedBuffer.release(); - } else { - throw new RuntimeException("Unexpected type: " + packagedBuffer.getClass()); - } - return output; - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieCheckTaskTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieCheckTaskTest.java deleted file mode 100644 index e915434623c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieCheckTaskTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyCollection; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Sets; -import com.google.common.collect.Maps; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link AuditorBookieCheckTask}. - */ -public class AuditorBookieCheckTaskTest { - - private AuditorStats auditorStats; - private BookKeeperAdmin admin; - private LedgerManager ledgerManager; - private LedgerUnderreplicationManager underreplicationManager; - private BookieLedgerIndexer ledgerIndexer; - private AuditorBookieCheckTask bookieCheckTask; - private final AtomicBoolean shutdownCompleted = new AtomicBoolean(false); - private final AuditorTask.ShutdownTaskHandler shutdownTaskHandler = () -> shutdownCompleted.set(true); - private long startLedgerId = 0; - - @Before - public void setup() { - ServerConfiguration conf = mock(ServerConfiguration.class); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsProvider.TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - final AuditorStats auditorStats = new AuditorStats(statsLogger); - this.auditorStats = spy(auditorStats); - admin = mock(BookKeeperAdmin.class); - ledgerManager = mock(LedgerManager.class); - underreplicationManager = mock(LedgerUnderreplicationManager.class); - ledgerIndexer = mock(BookieLedgerIndexer.class); - AuditorBookieCheckTask bookieCheckTask1 = new AuditorBookieCheckTask( - conf, this.auditorStats, admin, ledgerManager, underreplicationManager, - shutdownTaskHandler, ledgerIndexer, null, null); - bookieCheckTask = spy(bookieCheckTask1); - } - - @Test - public void testShutdownAuditBookiesException() - throws BKException, ReplicationException.BKAuditException, InterruptedException { - doThrow(new ReplicationException.BKAuditException("test failed")) - .when(bookieCheckTask) - .auditBookies(); - bookieCheckTask.startAudit(true); - - assertTrue("shutdownTaskHandler should be execute.", shutdownCompleted.get()); - } - - @Test - public void testAuditBookies() - throws ReplicationException.UnavailableException, ReplicationException.BKAuditException, BKException { - final String bookieId1 = "127.0.0.1:1000"; - final String bookieId2 = "127.0.0.1:1001"; - final long bookie1LedgersCount = 10; - final long bookie2LedgersCount = 20; - - final Map> bookiesAndLedgers = Maps.newHashMap(); - bookiesAndLedgers.put(bookieId1, getLedgers(bookie1LedgersCount)); - bookiesAndLedgers.put(bookieId2, getLedgers(bookie2LedgersCount)); - when(ledgerIndexer.getBookieToLedgerIndex()).thenReturn(bookiesAndLedgers); - when(underreplicationManager.isLedgerReplicationEnabled()).thenReturn(true); - - CompletableFuture> metaPromise = new CompletableFuture<>(); - final LongVersion version = mock(LongVersion.class); - final LedgerMetadata metadata = mock(LedgerMetadata.class); - metaPromise.complete(new Versioned<>(metadata, version)); - when(ledgerManager.readLedgerMetadata(anyLong())).thenReturn(metaPromise); - - CompletableFuture markPromise = new CompletableFuture<>(); - markPromise.complete(null); - when(underreplicationManager.markLedgerUnderreplicatedAsync(anyLong(), anyCollection())) - .thenReturn(markPromise); - - OpStatsLogger numUnderReplicatedLedgerStats = mock(OpStatsLogger.class); - when(auditorStats.getNumUnderReplicatedLedger()).thenReturn(numUnderReplicatedLedgerStats); - - final List availableBookies = Lists.newArrayList(); - final List readOnlyBookies = Lists.newArrayList(); - // test bookie1 lost - availableBookies.add(BookieId.parse(bookieId2)); - when(admin.getAvailableBookies()).thenReturn(availableBookies); - when(admin.getReadOnlyBookies()).thenReturn(readOnlyBookies); - bookieCheckTask.startAudit(true); - verify(numUnderReplicatedLedgerStats, times(1)) - .registerSuccessfulValue(eq(bookie1LedgersCount)); - - // test bookie2 lost - numUnderReplicatedLedgerStats = mock(OpStatsLogger.class); - when(auditorStats.getNumUnderReplicatedLedger()).thenReturn(numUnderReplicatedLedgerStats); - availableBookies.clear(); - availableBookies.add(BookieId.parse(bookieId1)); - bookieCheckTask.startAudit(true); - verify(numUnderReplicatedLedgerStats, times(1)) - .registerSuccessfulValue(eq(bookie2LedgersCount)); - - } - - private Set getLedgers(long count) { - final Set ledgers = Sets.newHashSet(); - for (int i = 0; i < count; i++) { - ledgers.add(i + startLedgerId++); - } - return ledgers; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieTest.java deleted file mode 100644 index 1bf56983624..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieTest.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.zookeeper.ZooKeeper; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This test verifies the auditor bookie scenarios which will be monitoring the - * bookie failures. - */ -public class AuditorBookieTest extends BookKeeperClusterTestCase { - // Depending on the taste, select the amount of logging - // by decommenting one of the two lines below - // private static final Logger LOG = Logger.getRootLogger(); - private static final Logger LOG = LoggerFactory - .getLogger(AuditorBookieTest.class); - private String electionPath; - private HashMap auditorElectors = new HashMap(); - private List zkClients = new LinkedList(); - - public AuditorBookieTest() { - super(6); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - startAuditorElectors(); - - electionPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf) - + "/underreplication/auditorelection"; - } - - @Override - public void tearDown() throws Exception { - stopAuditorElectors(); - for (ZooKeeper zk : zkClients) { - zk.close(); - } - zkClients.clear(); - super.tearDown(); - } - - /** - * Test should ensure only one should act as Auditor. Starting/shutdown - * other than auditor bookie shouldn't initiate re-election and multiple - * auditors. - */ - @Test - public void testEnsureOnlySingleAuditor() throws Exception { - BookieServer auditor = verifyAuditor(); - - // shutdown bookie which is not an auditor - int indexOf = indexOfServer(auditor); - int bkIndexDownBookie; - if (indexOf < lastBookieIndex()) { - bkIndexDownBookie = indexOf + 1; - } else { - bkIndexDownBookie = indexOf - 1; - } - shutdownBookie(serverByIndex(bkIndexDownBookie)); - - startNewBookie(); - startNewBookie(); - // grace period for the auditor re-election if any - BookieServer newAuditor = waitForNewAuditor(auditor); - assertSame( - "Auditor re-election is not happened for auditor failure!", - auditor, newAuditor); - } - - /** - * Test Auditor crashes should trigger re-election and another bookie should - * take over the auditor ship. - */ - @Test - public void testSuccessiveAuditorCrashes() throws Exception { - BookieServer auditor = verifyAuditor(); - shutdownBookie(auditor); - - BookieServer newAuditor1 = waitForNewAuditor(auditor); - shutdownBookie(newAuditor1); - BookieServer newAuditor2 = waitForNewAuditor(newAuditor1); - assertNotSame( - "Auditor re-election is not happened for auditor failure!", - auditor, newAuditor2); - } - - /** - * Test restarting the entire bookie cluster. It shouldn't create multiple - * bookie auditors. - */ - @Test - public void testBookieClusterRestart() throws Exception { - BookieServer auditor = verifyAuditor(); - for (AuditorElector auditorElector : auditorElectors.values()) { - assertTrue("Auditor elector is not running!", auditorElector - .isRunning()); - } - stopBKCluster(); - stopAuditorElectors(); - - startBKCluster(zkUtil.getMetadataServiceUri()); - startAuditorElectors(); - BookieServer newAuditor = waitForNewAuditor(auditor); - assertNotSame( - "Auditor re-election is not happened for auditor failure!", - auditor, newAuditor); - } - - /** - * Test the vote is deleting from the ZooKeeper during shutdown. - */ - @Test - public void testShutdown() throws Exception { - BookieServer auditor = verifyAuditor(); - shutdownBookie(auditor); - - // waiting for new auditor - BookieServer newAuditor = waitForNewAuditor(auditor); - assertNotSame( - "Auditor re-election is not happened for auditor failure!", - auditor, newAuditor); - - List children = zkc.getChildren(electionPath, false); - for (String child : children) { - byte[] data = zkc.getData(electionPath + '/' + child, false, null); - String bookieIP = new String(data); - String addr = auditor.getBookieId().toString(); - assertFalse("AuditorElection cleanup fails", bookieIP - .contains(addr)); - } - } - - /** - * Test restart of the previous Auditor bookie shouldn't initiate - * re-election and should create new vote after restarting. - */ - @Test - public void testRestartAuditorBookieAfterCrashing() throws Exception { - BookieServer auditor = verifyAuditor(); - - String addr = auditor.getBookieId().toString(); - - // restarting Bookie with same configurations. - ServerConfiguration serverConfiguration = shutdownBookie(auditor); - - auditorElectors.remove(addr); - startBookie(serverConfiguration); - // starting corresponding auditor elector - - if (LOG.isDebugEnabled()) { - LOG.debug("Performing Auditor Election:" + addr); - } - startAuditorElector(addr); - - // waiting for new auditor to come - BookieServer newAuditor = waitForNewAuditor(auditor); - assertNotSame( - "Auditor re-election is not happened for auditor failure!", - auditor, newAuditor); - assertFalse("No relection after old auditor rejoins", auditor - .getBookieId().equals(newAuditor.getBookieId())); - } - - private void startAuditorElector(String addr) throws Exception { - AuditorElector auditorElector = new AuditorElector(addr, - baseConf); - auditorElectors.put(addr, auditorElector); - auditorElector.start(); - if (LOG.isDebugEnabled()) { - LOG.debug("Starting Auditor Elector"); - } - } - - private void startAuditorElectors() throws Exception { - for (BookieId addr : bookieAddresses()) { - startAuditorElector(addr.toString()); - } - } - - private void stopAuditorElectors() throws Exception { - for (AuditorElector auditorElector : auditorElectors.values()) { - auditorElector.shutdown(); - if (LOG.isDebugEnabled()) { - LOG.debug("Stopping Auditor Elector!"); - } - } - } - - private BookieServer verifyAuditor() throws Exception { - List auditors = getAuditorBookie(); - assertEquals("Multiple Bookies acting as Auditor!", 1, auditors - .size()); - if (LOG.isDebugEnabled()) { - LOG.debug("Bookie running as Auditor:" + auditors.get(0)); - } - return auditors.get(0); - } - - private List getAuditorBookie() throws Exception { - List auditors = new LinkedList(); - byte[] data = zkc.getData(electionPath, false, null); - assertNotNull("Auditor election failed", data); - for (int i = 0; i < bookieCount(); i++) { - BookieServer bks = serverByIndex(i); - if (new String(data).contains(bks.getBookieId() + "")) { - auditors.add(bks); - } - } - return auditors; - } - - private ServerConfiguration shutdownBookie(BookieServer bkServer) throws Exception { - int index = indexOfServer(bkServer); - String addr = addressByIndex(index).toString(); - if (LOG.isDebugEnabled()) { - LOG.debug("Shutting down bookie:" + addr); - } - - // shutdown bookie which is an auditor - ServerConfiguration conf = killBookie(index); - - // stopping corresponding auditor elector - auditorElectors.get(addr).shutdown(); - return conf; - } - - private BookieServer waitForNewAuditor(BookieServer auditor) - throws Exception { - BookieServer newAuditor = null; - int retryCount = 8; - while (retryCount > 0) { - try { - List auditors = getAuditorBookie(); - if (auditors.size() > 0) { - newAuditor = auditors.get(0); - if (auditor != newAuditor) { - break; - } - } - } catch (Exception ignore) { - } - Thread.sleep(500); - retryCount--; - } - assertNotNull( - "New Auditor is not reelected after auditor crashes", - newAuditor); - verifyAuditor(); - return newAuditor; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorCheckAllLedgersTaskTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorCheckAllLedgersTaskTest.java deleted file mode 100644 index 02f585306f5..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorCheckAllLedgersTaskTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.junit.Assert.assertEquals; - -import java.util.LinkedList; -import java.util.List; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit test {@link AuditorCheckAllLedgersTask}. - */ -public class AuditorCheckAllLedgersTaskTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory - .getLogger(AuditorCheckAllLedgersTaskTest.class); - - private static final int maxNumberOfConcurrentOpenLedgerOperations = 500; - private static final int acquireConcurrentOpenLedgerOperationsTimeoutMSec = 120000; - - private BookKeeperAdmin admin; - private LedgerManager ledgerManager; - private LedgerUnderreplicationManager ledgerUnderreplicationManager; - - public AuditorCheckAllLedgersTaskTest() { - super(3); - baseConf.setPageLimit(1); - baseConf.setAutoRecoveryDaemonEnabled(false); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - final BookKeeper bookKeeper = new BookKeeper(baseClientConf); - admin = new BookKeeperAdmin(bookKeeper, NullStatsLogger.INSTANCE, new ClientConfiguration(baseClientConf)); - LedgerManagerFactory ledgerManagerFactory = bookKeeper.getLedgerManagerFactory(); - ledgerManager = ledgerManagerFactory.newLedgerManager(); - ledgerUnderreplicationManager = ledgerManagerFactory.newLedgerUnderreplicationManager(); - baseConf.setAuditorMaxNumberOfConcurrentOpenLedgerOperations(maxNumberOfConcurrentOpenLedgerOperations); - baseConf.setAuditorAcquireConcurrentOpenLedgerOperationsTimeoutMSec( - acquireConcurrentOpenLedgerOperationsTimeoutMSec); - } - - @Test - public void testCheckAllLedgers() throws Exception { - // 1. create ledgers - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - // 2. init CheckAllLedgersTask - final TestStatsProvider statsProvider = new TestStatsProvider(); - final TestStatsProvider.TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - final AuditorStats auditorStats = new AuditorStats(statsLogger); - - AuditorCheckAllLedgersTask auditorCheckAllLedgersTask = new AuditorCheckAllLedgersTask( - baseConf, auditorStats, admin, ledgerManager, - ledgerUnderreplicationManager, null, (flag, throwable) -> flag.set(false)); - - // 3. checkAllLedgers - auditorCheckAllLedgersTask.runTask(); - - // 4. verify - assertEquals("CHECK_ALL_LEDGERS_TIME", 1, ((TestStatsProvider.TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.CHECK_ALL_LEDGERS_TIME)).getSuccessCount()); - assertEquals("NUM_LEDGERS_CHECKED", numLedgers, - (long) statsLogger.getCounter(ReplicationStats.NUM_LEDGERS_CHECKED).get()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorLedgerCheckerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorLedgerCheckerTest.java deleted file mode 100644 index 2e3e09012fb..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorLedgerCheckerTest.java +++ /dev/null @@ -1,1122 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import lombok.Cleanup; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.MetadataClientDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.UnderreplicatedLedger; -import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.replication.ReplicationException.CompatibilityException; -import org.apache.bookkeeper.replication.ReplicationException.UnavailableException; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests publishing of under replicated ledgers by the Auditor bookie node when - * corresponding bookies identifes as not running. - */ -public class AuditorLedgerCheckerTest extends BookKeeperClusterTestCase { - - // Depending on the taste, select the amount of logging - // by decommenting one of the two lines below - // private static final Logger LOG = Logger.getRootLogger(); - private static final Logger LOG = LoggerFactory - .getLogger(AuditorLedgerCheckerTest.class); - - private static final byte[] ledgerPassword = "aaa".getBytes(); - private Random rng; // Random Number Generator - - private DigestType digestType; - - private String underreplicatedPath; - private Map auditorElectors = new ConcurrentHashMap<>(); - private ZkLedgerUnderreplicationManager urLedgerMgr; - private Set urLedgerList; - private String electionPath; - - private List ledgerList; - - public AuditorLedgerCheckerTest() - throws IOException, KeeperException, InterruptedException, - CompatibilityException { - this("org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"); - } - - AuditorLedgerCheckerTest(String ledgerManagerFactoryClass) - throws IOException, KeeperException, InterruptedException, - CompatibilityException { - super(3); - LOG.info("Running test case using ledger manager : " - + ledgerManagerFactoryClass); - this.digestType = DigestType.CRC32; - // set ledger manager name - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactoryClass); - baseClientConf - .setLedgerManagerFactoryClassName(ledgerManagerFactoryClass); - } - - @Before - public void setUp() throws Exception { - super.setUp(); - underreplicatedPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseClientConf) - + "/underreplication/ledgers"; - electionPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf) - + "/underreplication/auditorelection"; - - urLedgerMgr = new ZkLedgerUnderreplicationManager(baseClientConf, zkc); - urLedgerMgr.setCheckAllLedgersCTime(System.currentTimeMillis()); - startAuditorElectors(); - rng = new Random(System.currentTimeMillis()); // Initialize the Random - urLedgerList = new HashSet(); - ledgerList = new ArrayList(2); - baseClientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - } - - @Override - public void tearDown() throws Exception { - stopAuditorElectors(); - super.tearDown(); - } - - private void startAuditorElectors() throws Exception { - for (String addr : bookieAddresses().stream().map(Object::toString) - .collect(Collectors.toList())) { - AuditorElector auditorElector = new AuditorElector(addr, baseConf); - auditorElectors.put(addr, auditorElector); - auditorElector.start(); - if (LOG.isDebugEnabled()) { - LOG.debug("Starting Auditor Elector"); - } - } - } - - private void stopAuditorElectors() throws Exception { - for (AuditorElector auditorElector : auditorElectors.values()) { - auditorElector.shutdown(); - if (LOG.isDebugEnabled()) { - LOG.debug("Stopping Auditor Elector!"); - } - } - } - - /** - * Test publishing of under replicated ledgers by the auditor bookie. - */ - @Test - public void testSimpleLedger() throws Exception { - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList - .size()); - - int bkShutdownIndex = lastBookieIndex(); - String shutdownBookie = shutdownBookie(bkShutdownIndex); - - // grace period for publishing the bk-ledger - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - waitForAuditToComplete(); - underReplicaLatch.await(5, TimeUnit.SECONDS); - Map urLedgerData = getUrLedgerData(urLedgerList); - assertEquals("Missed identifying under replicated ledgers", 1, - urLedgerList.size()); - - /* - * Sample data format present in the under replicated ledger path - * - * {4=replica: "10.18.89.153:5002"} - */ - assertTrue("Ledger is not marked as underreplicated:" + ledgerId, - urLedgerList.contains(ledgerId)); - String data = urLedgerData.get(ledgerId); - assertTrue("Bookie " + shutdownBookie - + "is not listed in the ledger as missing replica :" + data, - data.contains(shutdownBookie)); - } - - /** - * Test once published under replicated ledger should exists even after - * restarting respective bookie. - */ - @Test - public void testRestartBookie() throws Exception { - LedgerHandle lh1 = createAndAddEntriesToLedger(); - LedgerHandle lh2 = createAndAddEntriesToLedger(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Created following ledgers : {}, {}", lh1, lh2); - } - - int bkShutdownIndex = lastBookieIndex(); - ServerConfiguration bookieConf1 = confByIndex(bkShutdownIndex); - String shutdownBookie = shutdownBookie(bkShutdownIndex); - - // restart the failed bookie - startAndAddBookie(bookieConf1); - - waitForLedgerMissingReplicas(lh1.getId(), 10, shutdownBookie); - waitForLedgerMissingReplicas(lh2.getId(), 10, shutdownBookie); - } - - /** - * Test publishing of under replicated ledgers when multiple bookie failures - * one after another. - */ - @Test - public void testMultipleBookieFailures() throws Exception { - LedgerHandle lh1 = createAndAddEntriesToLedger(); - - // failing first bookie - shutdownBookie(lastBookieIndex()); - - // simulate re-replication - doLedgerRereplication(lh1.getId()); - - // failing another bookie - String shutdownBookie = shutdownBookie(lastBookieIndex()); - - // grace period for publishing the bk-ledger - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - assertTrue("Ledger should be missing second replica", - waitForLedgerMissingReplicas(lh1.getId(), 10, shutdownBookie)); - } - - @Test - public void testToggleLedgerReplication() throws Exception { - LedgerHandle lh1 = createAndAddEntriesToLedger(); - ledgerList.add(lh1.getId()); - if (LOG.isDebugEnabled()) { - LOG.debug("Created following ledgers : " + ledgerList); - } - - // failing another bookie - CountDownLatch urReplicaLatch = registerUrLedgerWatcher(ledgerList - .size()); - - // disabling ledger replication - urLedgerMgr.disableLedgerReplication(); - ArrayList shutdownBookieList = new ArrayList(); - shutdownBookieList.add(shutdownBookie(lastBookieIndex())); - shutdownBookieList.add(shutdownBookie(lastBookieIndex())); - - assertFalse("Ledger replication is not disabled!", urReplicaLatch - .await(1, TimeUnit.SECONDS)); - - // enabling ledger replication - urLedgerMgr.enableLedgerReplication(); - assertTrue("Ledger replication is not enabled!", urReplicaLatch.await( - 5, TimeUnit.SECONDS)); - } - - @Test - public void testDuplicateEnDisableAutoRecovery() throws Exception { - urLedgerMgr.disableLedgerReplication(); - try { - urLedgerMgr.disableLedgerReplication(); - fail("Must throw exception, since AutoRecovery is already disabled"); - } catch (UnavailableException e) { - assertTrue("AutoRecovery is not disabled previously!", - e.getCause() instanceof KeeperException.NodeExistsException); - } - urLedgerMgr.enableLedgerReplication(); - try { - urLedgerMgr.enableLedgerReplication(); - fail("Must throw exception, since AutoRecovery is already enabled"); - } catch (UnavailableException e) { - assertTrue("AutoRecovery is not enabled previously!", - e.getCause() instanceof KeeperException.NoNodeException); - } - } - - /** - * Test Auditor should consider Readonly bookie as available bookie. Should not publish ur ledgers for - * readonly bookies. - */ - @Test - public void testReadOnlyBookieExclusionFromURLedgersCheck() throws Exception { - LedgerHandle lh = createAndAddEntriesToLedger(); - ledgerList.add(lh.getId()); - if (LOG.isDebugEnabled()) { - LOG.debug("Created following ledgers : " + ledgerList); - } - - int count = ledgerList.size(); - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(count); - - final int bkIndex = 2; - ServerConfiguration bookieConf = confByIndex(bkIndex); - BookieServer bk = serverByIndex(bkIndex); - bookieConf.setReadOnlyModeEnabled(true); - - ((BookieImpl) bk.getBookie()).getStateManager().doTransitionToReadOnlyMode(); - bkc.waitForReadOnlyBookie(BookieImpl.getBookieId(confByIndex(bkIndex))) - .get(30, TimeUnit.SECONDS); - - // grace period for publishing the bk-ledger - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for Auditor to finish ledger check."); - } - waitForAuditToComplete(); - assertFalse("latch should not have completed", underReplicaLatch.await(5, TimeUnit.SECONDS)); - } - - /** - * Test Auditor should consider Readonly bookie fail and publish ur ledgers for readonly bookies. - */ - @Test - public void testReadOnlyBookieShutdown() throws Exception { - LedgerHandle lh = createAndAddEntriesToLedger(); - long ledgerId = lh.getId(); - ledgerList.add(ledgerId); - if (LOG.isDebugEnabled()) { - LOG.debug("Created following ledgers : " + ledgerList); - } - - int count = ledgerList.size(); - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(count); - - int bkIndex = lastBookieIndex(); - if (LOG.isDebugEnabled()) { - LOG.debug("Moving bookie {} {} to read only...", bkIndex, serverByIndex(bkIndex)); - } - ServerConfiguration bookieConf = confByIndex(bkIndex); - BookieServer bk = serverByIndex(bkIndex); - bookieConf.setReadOnlyModeEnabled(true); - - ((BookieImpl) bk.getBookie()).getStateManager().doTransitionToReadOnlyMode(); - bkc.waitForReadOnlyBookie(BookieImpl.getBookieId(confByIndex(bkIndex))) - .get(30, TimeUnit.SECONDS); - - // grace period for publishing the bk-ledger - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for Auditor to finish ledger check."); - } - waitForAuditToComplete(); - assertFalse("latch should not have completed", underReplicaLatch.await(1, TimeUnit.SECONDS)); - - String shutdownBookie = shutdownBookie(bkIndex); - - // grace period for publishing the bk-ledger - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - waitForAuditToComplete(); - underReplicaLatch.await(5, TimeUnit.SECONDS); - Map urLedgerData = getUrLedgerData(urLedgerList); - assertEquals("Missed identifying under replicated ledgers", 1, urLedgerList.size()); - - /* - * Sample data format present in the under replicated ledger path - * - * {4=replica: "10.18.89.153:5002"} - */ - assertTrue("Ledger is not marked as underreplicated:" + ledgerId, urLedgerList.contains(ledgerId)); - String data = urLedgerData.get(ledgerId); - assertTrue("Bookie " + shutdownBookie + "is not listed in the ledger as missing replica :" + data, - data.contains(shutdownBookie)); - } - - public void testInnerDelayedAuditOfLostBookies() throws Exception { - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList - .size()); - - // wait for 5 seconds before starting the recovery work when a bookie fails - urLedgerMgr.setLostBookieRecoveryDelay(5); - - // shutdown a non auditor bookie; choosing non-auditor to avoid another election - AtomicReference shutdownBookieRef = new AtomicReference<>(); - CountDownLatch shutdownLatch = new CountDownLatch(1); - new Thread(() -> { - try { - String shutdownBookie = shutDownNonAuditorBookie(); - shutdownBookieRef.set(shutdownBookie); - shutdownLatch.countDown(); - } catch (Exception ignore) { - } - }).start(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(4, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - // wait for another 5 seconds for the ledger to get reported as under replicated - assertTrue("audit of lost bookie isn't delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - - assertTrue("Ledger is not marked as underreplicated:" + ledgerId, - urLedgerList.contains(ledgerId)); - Map urLedgerData = getUrLedgerData(urLedgerList); - String data = urLedgerData.get(ledgerId); - shutdownLatch.await(); - assertTrue("Bookie " + shutdownBookieRef.get() - + "is not listed in the ledger as missing replica :" + data, - data.contains(shutdownBookieRef.get())); - } - - /** - * Test publishing of under replicated ledgers by the auditor - * bookie is delayed if LostBookieRecoveryDelay option is set. - */ - @Test - public void testDelayedAuditOfLostBookies() throws Exception { - // wait for a second so that the initial periodic check finishes - Thread.sleep(1000); - - testInnerDelayedAuditOfLostBookies(); - } - - /** - * Test publishing of under replicated ledgers by the auditor - * bookie is delayed if LostBookieRecoveryDelay option is set - * and it continues to be delayed even when periodic bookie check - * is set to run every 2 secs. I.e. periodic bookie check doesn't - * override the delay - */ - @Test - public void testDelayedAuditWithPeriodicBookieCheck() throws Exception { - // enable periodic bookie check on a cadence of every 2 seconds. - // this requires us to stop the auditor/auditorElectors, set the - // periodic check interval and restart the auditorElectors - stopAuditorElectors(); - baseConf.setAuditorPeriodicBookieCheckInterval(2); - startAuditorElectors(); - - // wait for a second so that the initial periodic check finishes - Thread.sleep(1000); - - // the delaying of audit should just work despite the fact - // we have enabled periodic bookie check - testInnerDelayedAuditOfLostBookies(); - } - - @Test - public void testRescheduleOfDelayedAuditOfLostBookiesToStartImmediately() throws Exception { - // wait for a second so that the initial periodic check finishes - Thread.sleep(1000); - - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList - .size()); - - // wait for 50 seconds before starting the recovery work when a bookie fails - urLedgerMgr.setLostBookieRecoveryDelay(50); - - // shutdown a non auditor bookie; choosing non-auditor to avoid another election - AtomicReference shutdownBookieRef = new AtomicReference<>(); - CountDownLatch shutdownLatch = new CountDownLatch(1); - new Thread(() -> { - try { - String shutdownBookie = shutDownNonAuditorBookie(); - shutdownBookieRef.set(shutdownBookie); - shutdownLatch.countDown(); - } catch (Exception ignore) { - } - }).start(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(4, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - // set lostBookieRecoveryDelay to 0, so that it triggers AuditTask immediately - urLedgerMgr.setLostBookieRecoveryDelay(0); - - // wait for 1 second for the ledger to get reported as under replicated - assertTrue("audit of lost bookie isn't delayed", underReplicaLatch.await(1, TimeUnit.SECONDS)); - - assertTrue("Ledger is not marked as underreplicated:" + ledgerId, - urLedgerList.contains(ledgerId)); - Map urLedgerData = getUrLedgerData(urLedgerList); - String data = urLedgerData.get(ledgerId); - shutdownLatch.await(); - assertTrue("Bookie " + shutdownBookieRef.get() - + "is not listed in the ledger as missing replica :" + data, - data.contains(shutdownBookieRef.get())); - } - - @Test - public void testRescheduleOfDelayedAuditOfLostBookiesToStartLater() throws Exception { - // wait for a second so that the initial periodic check finishes - Thread.sleep(1000); - - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList - .size()); - - // wait for 3 seconds before starting the recovery work when a bookie fails - urLedgerMgr.setLostBookieRecoveryDelay(3); - - // shutdown a non auditor bookie; choosing non-auditor to avoid another election - AtomicReference shutdownBookieRef = new AtomicReference<>(); - CountDownLatch shutdownLatch = new CountDownLatch(1); - new Thread(() -> { - try { - String shutdownBookie = shutDownNonAuditorBookie(); - shutdownBookieRef.set(shutdownBookie); - shutdownLatch.countDown(); - } catch (Exception ignore) { - } - }).start(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - // set lostBookieRecoveryDelay to 4, so the pending AuditTask is resheduled - urLedgerMgr.setLostBookieRecoveryDelay(4); - - // since we changed the BookieRecoveryDelay period to 4, the audittask shouldn't have been executed - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - // wait for 3 seconds (since we already waited for 2 secs) for the ledger to get reported as under replicated - assertTrue("audit of lost bookie isn't delayed", underReplicaLatch.await(3, TimeUnit.SECONDS)); - assertTrue("Ledger is not marked as underreplicated:" + ledgerId, - urLedgerList.contains(ledgerId)); - Map urLedgerData = getUrLedgerData(urLedgerList); - String data = urLedgerData.get(ledgerId); - shutdownLatch.await(); - assertTrue("Bookie " + shutdownBookieRef.get() - + "is not listed in the ledger as missing replica :" + data, - data.contains(shutdownBookieRef.get())); - } - - @Test - public void testTriggerAuditorWithNoPendingAuditTask() throws Exception { - // wait for a second so that the initial periodic check finishes - Thread.sleep(1000); - int lostBookieRecoveryDelayConfValue = baseConf.getLostBookieRecoveryDelay(); - Auditor auditorBookiesAuditor = getAuditorBookiesAuditor(); - Future auditTask = auditorBookiesAuditor.getAuditTask(); - int lostBookieRecoveryDelayBeforeChange = auditorBookiesAuditor.getLostBookieRecoveryDelayBeforeChange(); - Assert.assertEquals("auditTask is supposed to be null", null, auditTask); - Assert.assertEquals( - "lostBookieRecoveryDelayBeforeChange of Auditor should be equal to BaseConf's lostBookieRecoveryDelay", - lostBookieRecoveryDelayConfValue, lostBookieRecoveryDelayBeforeChange); - - @Cleanup("shutdown") OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduler") - .numThreads(1) - .build(); - @Cleanup MetadataClientDriver driver = - MetadataDrivers.getClientDriver(URI.create(baseClientConf.getMetadataServiceUri())); - driver.initialize(baseClientConf, scheduler, NullStatsLogger.INSTANCE, Optional.of(zkc)); - - // there is no easy way to validate if the Auditor has executed Audit process (Auditor.startAudit), - // without shuttingdown Bookie. To test if by resetting LostBookieRecoveryDelay it does Auditing - // even when there is no pending AuditTask, following approach is needed. - - // Here we are creating few ledgers ledgermetadata with non-existing bookies as its ensemble. - // When Auditor does audit it recognizes these ledgers as underreplicated and mark them as - // under-replicated, since these bookies are not available. - int numofledgers = 5; - Random rand = new Random(); - for (int i = 0; i < numofledgers; i++) { - ArrayList ensemble = new ArrayList(); - ensemble.add(new BookieSocketAddress("99.99.99.99:9999").toBookieId()); - ensemble.add(new BookieSocketAddress("11.11.11.11:1111").toBookieId()); - ensemble.add(new BookieSocketAddress("88.88.88.88:8888").toBookieId()); - - long ledgerId = (Math.abs(rand.nextLong())) % 100000000; - - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(ledgerId) - .withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(2) - .withPassword("passwd".getBytes()) - .withDigestType(DigestType.CRC32.toApiDigestType()) - .newEnsembleEntry(0L, ensemble).build(); - - try (LedgerManager lm = driver.getLedgerManagerFactory().newLedgerManager()) { - lm.createLedgerMetadata(ledgerId, metadata).get(2000, TimeUnit.MILLISECONDS); - } - ledgerList.add(ledgerId); - } - - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList.size()); - urLedgerMgr.setLostBookieRecoveryDelay(lostBookieRecoveryDelayBeforeChange); - assertTrue("Audit should be triggered and created ledgers should be marked as underreplicated", - underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("All the ledgers should be marked as underreplicated", ledgerList.size(), urLedgerList.size()); - - auditTask = auditorBookiesAuditor.getAuditTask(); - Assert.assertEquals("auditTask is supposed to be null", null, auditTask); - Assert.assertEquals( - "lostBookieRecoveryDelayBeforeChange of Auditor should be equal to BaseConf's lostBookieRecoveryDelay", - lostBookieRecoveryDelayBeforeChange, auditorBookiesAuditor.getLostBookieRecoveryDelayBeforeChange()); - } - - @Test - public void testTriggerAuditorWithPendingAuditTask() throws Exception { - // wait for a second so that the initial periodic check finishes - Thread.sleep(1000); - - Auditor auditorBookiesAuditor = getAuditorBookiesAuditor(); - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList - .size()); - - int lostBookieRecoveryDelay = 5; - // wait for 5 seconds before starting the recovery work when a bookie fails - urLedgerMgr.setLostBookieRecoveryDelay(lostBookieRecoveryDelay); - - // shutdown a non auditor bookie; choosing non-auditor to avoid another election - new Thread(() -> { - try { - shutDownNonAuditorBookie(); - } catch (Exception ignore) { - } - }).start(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - Future auditTask = auditorBookiesAuditor.getAuditTask(); - Assert.assertNotEquals("auditTask is not supposed to be null", null, auditTask); - Assert.assertEquals( - "lostBookieRecoveryDelayBeforeChange of Auditor should be equal to what we set", - lostBookieRecoveryDelay, auditorBookiesAuditor.getLostBookieRecoveryDelayBeforeChange()); - - // set lostBookieRecoveryDelay to 5 (previous value), so that Auditor is triggered immediately - urLedgerMgr.setLostBookieRecoveryDelay(lostBookieRecoveryDelay); - assertTrue("audit of lost bookie shouldn't be delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("all under replicated ledgers should be identified", ledgerList.size(), - urLedgerList.size()); - - Thread.sleep(100); - auditTask = auditorBookiesAuditor.getAuditTask(); - Assert.assertEquals("auditTask is supposed to be null", null, auditTask); - Assert.assertEquals( - "lostBookieRecoveryDelayBeforeChange of Auditor should be equal to previously set value", - lostBookieRecoveryDelay, auditorBookiesAuditor.getLostBookieRecoveryDelayBeforeChange()); - } - - @Test - public void testTriggerAuditorBySettingDelayToZeroWithPendingAuditTask() throws Exception { - // wait for a second so that the initial periodic check finishes - Thread.sleep(1000); - - Auditor auditorBookiesAuditor = getAuditorBookiesAuditor(); - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - final CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList - .size()); - - int lostBookieRecoveryDelay = 5; - // wait for 5 seconds before starting the recovery work when a bookie fails - urLedgerMgr.setLostBookieRecoveryDelay(lostBookieRecoveryDelay); - - // shutdown a non auditor bookie; choosing non-auditor to avoid another election - new Thread(() -> { - try { - shutDownNonAuditorBookie(); - } catch (Exception ignore) { - } - }).start(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting for ledgers to be marked as under replicated"); - } - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - Future auditTask = auditorBookiesAuditor.getAuditTask(); - Assert.assertNotEquals("auditTask is not supposed to be null", null, auditTask); - Assert.assertEquals( - "lostBookieRecoveryDelayBeforeChange of Auditor should be equal to what we set", - lostBookieRecoveryDelay, auditorBookiesAuditor.getLostBookieRecoveryDelayBeforeChange()); - - // set lostBookieRecoveryDelay to 0, so that Auditor is triggered immediately - urLedgerMgr.setLostBookieRecoveryDelay(0); - assertTrue("audit of lost bookie shouldn't be delayed", underReplicaLatch.await(1, TimeUnit.SECONDS)); - assertEquals("all under replicated ledgers should be identified", ledgerList.size(), - urLedgerList.size()); - - Thread.sleep(100); - auditTask = auditorBookiesAuditor.getAuditTask(); - assertEquals("auditTask is supposed to be null", null, auditTask); - assertEquals( - "lostBookieRecoveryDelayBeforeChange of Auditor should be equal to previously set value", - 0, auditorBookiesAuditor.getLostBookieRecoveryDelayBeforeChange()); - } - - /** - * Test audit of bookies is delayed when one bookie is down. But when - * another one goes down, the audit is started immediately. - */ - @Test - public void testDelayedAuditWithMultipleBookieFailures() throws Exception { - // wait for the periodic bookie check to finish - Thread.sleep(1000); - - // create a ledger with a bunch of entries - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList.size()); - - // wait for 10 seconds before starting the recovery work when a bookie fails - urLedgerMgr.setLostBookieRecoveryDelay(10); - - // shutdown a non auditor bookie; choosing non-auditor to avoid another election - AtomicReference shutdownBookieRef1 = new AtomicReference<>(); - CountDownLatch shutdownLatch1 = new CountDownLatch(1); - new Thread(() -> { - try { - String shutdownBookie1 = shutDownNonAuditorBookie(); - shutdownBookieRef1.set(shutdownBookie1); - shutdownLatch1.countDown(); - } catch (Exception ignore) { - } - }).start(); - - // wait for 3 seconds and there shouldn't be any under replicated ledgers - // because we have delayed the start of audit by 10 seconds - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(3, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - // Now shutdown the second non auditor bookie; We want to make sure that - // the history about having delayed recovery remains. Hence we make sure - // we bring down a non auditor bookie. This should cause the audit to take - // place immediately and not wait for the remaining 7 seconds to elapse - AtomicReference shutdownBookieRef2 = new AtomicReference<>(); - CountDownLatch shutdownLatch2 = new CountDownLatch(1); - new Thread(() -> { - try { - String shutdownBookie2 = shutDownNonAuditorBookie(); - shutdownBookieRef2.set(shutdownBookie2); - shutdownLatch2.countDown(); - } catch (Exception ignore) { - } - }).start(); - - // 2 second grace period for the ledgers to get reported as under replicated - Thread.sleep(2000); - - // If the following checks pass, it means that audit happened - // within 2 seconds of second bookie going down and it didn't - // wait for 7 more seconds. Hence the second bookie failure doesn't - // delay the audit - assertTrue("Ledger is not marked as underreplicated:" + ledgerId, - urLedgerList.contains(ledgerId)); - Map urLedgerData = getUrLedgerData(urLedgerList); - String data = urLedgerData.get(ledgerId); - shutdownLatch1.await(); - shutdownLatch2.await(); - assertTrue("Bookie " + shutdownBookieRef1.get() + shutdownBookieRef2.get() - + " are not listed in the ledger as missing replicas :" + data, - data.contains(shutdownBookieRef1.get()) && data.contains(shutdownBookieRef2.get())); - } - - /** - * Test audit of bookies is delayed during rolling upgrade scenario: - * a bookies goes down and comes up, the next bookie go down and up and so on. - * At any time only one bookie is down. - */ - @Test - public void testDelayedAuditWithRollingUpgrade() throws Exception { - // wait for the periodic bookie check to finish - Thread.sleep(1000); - - // create a ledger with a bunch of entries - LedgerHandle lh1 = createAndAddEntriesToLedger(); - Long ledgerId = lh1.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Created ledger : " + ledgerId); - } - ledgerList.add(ledgerId); - lh1.close(); - - CountDownLatch underReplicaLatch = registerUrLedgerWatcher(ledgerList.size()); - - // wait for 5 seconds before starting the recovery work when a bookie fails - urLedgerMgr.setLostBookieRecoveryDelay(5); - - // shutdown a non auditor bookie to avoid an election - int idx1 = getShutDownNonAuditorBookieIdx(""); - ServerConfiguration conf1 = confByIndex(idx1); - - AtomicReference shutdownBookieRef1 = new AtomicReference<>(); - CountDownLatch shutdownLatch1 = new CountDownLatch(1); - new Thread(() -> { - try { - String shutdownBookie1 = shutdownBookie(idx1); - shutdownBookieRef1.set(shutdownBookie1); - shutdownLatch1.countDown(); - } catch (Exception ignore) { - } - }).start(); - - // wait for 2 seconds and there shouldn't be any under replicated ledgers - // because we have delayed the start of audit by 5 seconds - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - // restart the bookie we shut down above - startAndAddBookie(conf1); - - // Now to simulate the rolling upgrade, bring down a bookie different from - // the one we brought down/up above. - // shutdown a non auditor bookie; choosing non-auditor to avoid another election - AtomicReference shutdownBookieRef2 = new AtomicReference<>(); - CountDownLatch shutdownLatch2 = new CountDownLatch(1); - new Thread(() -> { - try { - String shutdownBookie2 = shutDownNonAuditorBookie(); - shutdownBookieRef2.set(shutdownBookie2); - shutdownLatch2.countDown(); - } catch (Exception ignore) { - } - }).start(); - // since the first bookie that was brought down/up has come up, there is only - // one bookie down at this time. Hence the lost bookie check shouldn't start - // immediately; it will start 5 seconds after the second bookie went down - assertFalse("audit of lost bookie isn't delayed", underReplicaLatch.await(2, TimeUnit.SECONDS)); - assertEquals("under replicated ledgers identified when it was not expected", 0, - urLedgerList.size()); - - // wait for a total of 6 seconds(2+4) for the ledgers to get reported as under replicated - Thread.sleep(4000); - - // If the following checks pass, it means that auditing happened - // after lostBookieRecoveryDelay during rolling upgrade as expected - assertTrue("Ledger is not marked as underreplicated:" + ledgerId, - urLedgerList.contains(ledgerId)); - Map urLedgerData = getUrLedgerData(urLedgerList); - String data = urLedgerData.get(ledgerId); - shutdownLatch1.await(); - shutdownLatch2.await(); - assertTrue("Bookie " + shutdownBookieRef1.get() + "wrongly listed as missing the ledger: " + data, - !data.contains(shutdownBookieRef1.get())); - assertTrue("Bookie " + shutdownBookieRef2.get() - + " is not listed in the ledger as missing replicas :" + data, - data.contains(shutdownBookieRef2.get())); - LOG.info("*****************Test Complete"); - } - - private void waitForAuditToComplete() throws Exception { - long endTime = System.currentTimeMillis() + 5_000; - while (System.currentTimeMillis() < endTime) { - Auditor auditor = getAuditorBookiesAuditor(); - if (auditor != null) { - Future task = auditor.submitAuditTask(); - task.get(5, TimeUnit.SECONDS); - return; - } - Thread.sleep(100); - } - throw new TimeoutException("Could not find an audit within 5 seconds"); - } - - /** - * Wait for ledger to be underreplicated, and to be missing all replicas specified. - */ - private boolean waitForLedgerMissingReplicas(Long ledgerId, long secondsToWait, String... replicas) - throws Exception { - for (int i = 0; i < secondsToWait; i++) { - try { - UnderreplicatedLedger data = urLedgerMgr.getLedgerUnreplicationInfo(ledgerId); - boolean all = true; - for (String r : replicas) { - all = all && data.getReplicaList().contains(r); - } - if (all) { - return true; - } - } catch (Exception e) { - // may not find node - } - Thread.sleep(1000); - } - return false; - } - - private CountDownLatch registerUrLedgerWatcher(int count) - throws KeeperException, InterruptedException { - final CountDownLatch underReplicaLatch = new CountDownLatch(count); - for (Long ledgerId : ledgerList) { - Watcher urLedgerWatcher = new ChildWatcher(underReplicaLatch); - String znode = ZkLedgerUnderreplicationManager.getUrLedgerZnode(underreplicatedPath, - ledgerId); - zkc.exists(znode, urLedgerWatcher); - } - return underReplicaLatch; - } - - private void doLedgerRereplication(Long... ledgerIds) - throws UnavailableException { - for (int i = 0; i < ledgerIds.length; i++) { - long lid = urLedgerMgr.getLedgerToRereplicate(); - assertTrue("Received unexpected ledgerid", Arrays.asList(ledgerIds).contains(lid)); - urLedgerMgr.markLedgerReplicated(lid); - urLedgerMgr.releaseUnderreplicatedLedger(lid); - } - } - - private String shutdownBookie(int bkShutdownIndex) throws Exception { - BookieServer bkServer = serverByIndex(bkShutdownIndex); - String bookieAddr = bkServer.getBookieId().toString(); - if (LOG.isDebugEnabled()) { - LOG.debug("Shutting down bookie:" + bookieAddr); - } - killBookie(bkShutdownIndex); - auditorElectors.get(bookieAddr).shutdown(); - auditorElectors.remove(bookieAddr); - return bookieAddr; - } - - private LedgerHandle createAndAddEntriesToLedger() throws BKException, - InterruptedException { - int numEntriesToWrite = 100; - // Create a ledger - LedgerHandle lh = bkc.createLedger(digestType, ledgerPassword); - LOG.info("Ledger ID: " + lh.getId()); - addEntry(numEntriesToWrite, lh); - return lh; - } - - private void addEntry(int numEntriesToWrite, LedgerHandle lh) - throws InterruptedException, BKException { - final CountDownLatch completeLatch = new CountDownLatch(numEntriesToWrite); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(Integer.MAX_VALUE)); - entry.position(0); - lh.asyncAddEntry(entry.array(), new AddCallback() { - public void addComplete(int rc2, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rc2); - completeLatch.countDown(); - } - }, null); - } - completeLatch.await(); - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - - } - - private Map getUrLedgerData(Set urLedgerList) - throws KeeperException, InterruptedException { - Map urLedgerData = new HashMap(); - for (Long ledgerId : urLedgerList) { - String znode = ZkLedgerUnderreplicationManager.getUrLedgerZnode(underreplicatedPath, - ledgerId); - byte[] data = zkc.getData(znode, false, null); - urLedgerData.put(ledgerId, new String(data)); - } - return urLedgerData; - } - - private class ChildWatcher implements Watcher { - private final CountDownLatch underReplicaLatch; - - public ChildWatcher(CountDownLatch underReplicaLatch) { - this.underReplicaLatch = underReplicaLatch; - } - - @Override - public void process(WatchedEvent event) { - LOG.info("Received notification for the ledger path : " - + event.getPath()); - for (Long ledgerId : ledgerList) { - if (event.getPath().contains(ledgerId + "")) { - urLedgerList.add(ledgerId); - } - } - if (LOG.isDebugEnabled()) { - LOG.debug("Count down and waiting for next notification"); - } - // count down and waiting for next notification - underReplicaLatch.countDown(); - } - } - - private BookieServer getAuditorBookie() throws Exception { - List auditors = new LinkedList(); - byte[] data = zkc.getData(electionPath, false, null); - assertNotNull("Auditor election failed", data); - for (int i = 0; i < bookieCount(); i++) { - BookieId bookieId = addressByIndex(i); - if (new String(data).contains(bookieId + "")) { - auditors.add(serverByIndex(i)); - } - } - assertEquals("Multiple Bookies acting as Auditor!", 1, auditors - .size()); - return auditors.get(0); - } - - private Auditor getAuditorBookiesAuditor() throws Exception { - BookieServer auditorBookieServer = getAuditorBookie(); - String bookieAddr = auditorBookieServer.getBookieId().toString(); - return auditorElectors.get(bookieAddr).auditor; - } - - private String shutDownNonAuditorBookie() throws Exception { - // shutdown bookie which is not an auditor - int indexOf = indexOfServer(getAuditorBookie()); - int bkIndexDownBookie; - if (indexOf < lastBookieIndex()) { - bkIndexDownBookie = indexOf + 1; - } else { - bkIndexDownBookie = indexOf - 1; - } - return shutdownBookie(bkIndexDownBookie); - } - - private int getShutDownNonAuditorBookieIdx(String exclude) throws Exception { - // shutdown bookie which is not an auditor - int indexOf = indexOfServer(getAuditorBookie()); - int bkIndexDownBookie = 0; - for (int i = 0; i <= lastBookieIndex(); i++) { - if (i == indexOf || addressByIndex(i).toString().equals(exclude)) { - continue; - } - bkIndexDownBookie = i; - break; - } - return bkIndexDownBookie; - } - - private String shutDownNonAuditorBookie(String exclude) throws Exception { - return shutdownBookie(getShutDownNonAuditorBookieIdx(exclude)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicBookieCheckTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicBookieCheckTest.java deleted file mode 100644 index 5d25ce76e94..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicBookieCheckTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.UncheckedExecutionException; -import lombok.Cleanup; -import org.apache.bookkeeper.client.ClientUtil; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This test verifies that the period check on the auditor - * will pick up on missing data in the client. - */ -public class AuditorPeriodicBookieCheckTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory - .getLogger(AuditorPeriodicBookieCheckTest.class); - - private AuditorElector auditorElector = null; - - private static final int CHECK_INTERVAL = 1; // run every second - - public AuditorPeriodicBookieCheckTest() { - super(3); - baseConf.setPageLimit(1); // to make it easy to push ledger out of cache - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setAuditorPeriodicBookieCheckInterval(CHECK_INTERVAL); - conf.setMetadataServiceUri(metadataServiceUri); - conf.setProperty("clientConnectTimeoutMillis", 500); - String addr = addressByIndex(0).toString(); - - auditorElector = new AuditorElector(addr, conf); - auditorElector.start(); - } - - @After - @Override - public void tearDown() throws Exception { - auditorElector.shutdown(); - - super.tearDown(); - } - - /** - * Test that the periodic bookie checker works. - */ - @Test - public void testPeriodicBookieCheckInterval() throws Exception { - confByIndex(0).setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - runFunctionWithLedgerManagerFactory(confByIndex(0), mFactory -> { - try (LedgerManager ledgerManager = mFactory.newLedgerManager()) { - @Cleanup final LedgerUnderreplicationManager underReplicationManager = - mFactory.newLedgerUnderreplicationManager(); - long ledgerId = 12345L; - ClientUtil.setupLedger(bkc.getLedgerManager(), ledgerId, - LedgerMetadataBuilder.create().withEnsembleSize(3) - .withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList( - new BookieSocketAddress("192.0.2.1", 1000).toBookieId(), - getBookie(0), - getBookie(1)))); - long underReplicatedLedger = -1; - for (int i = 0; i < 10; i++) { - underReplicatedLedger = underReplicationManager.pollLedgerToRereplicate(); - if (underReplicatedLedger != -1) { - break; - } - Thread.sleep(CHECK_INTERVAL * 1000); - } - assertEquals("Ledger should be under replicated", ledgerId, underReplicatedLedger); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - return null; - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java deleted file mode 100644 index 53e139b19e8..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java +++ /dev/null @@ -1,1076 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.net.URI; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieAccessor; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.IndexPersistenceMgr; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.replication.ReplicationException.UnavailableException; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.awaitility.Awaitility; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This test verifies that the period check on the auditor - * will pick up on missing data in the client. - */ -public class AuditorPeriodicCheckTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory - .getLogger(AuditorPeriodicCheckTest.class); - - private MetadataBookieDriver driver; - private HashMap auditorElectors = new HashMap(); - - private static final int CHECK_INTERVAL = 1; // run every second - - public AuditorPeriodicCheckTest() { - super(3); - baseConf.setPageLimit(1); // to make it easy to push ledger out of cache - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - - for (int i = 0; i < numBookies; i++) { - ServerConfiguration conf = new ServerConfiguration(confByIndex(i)); - conf.setAuditorPeriodicCheckInterval(CHECK_INTERVAL); - - String addr = addressByIndex(i).toString(); - - AuditorElector auditorElector = new AuditorElector(addr, conf); - auditorElectors.put(addr, auditorElector); - auditorElector.start(); - if (LOG.isDebugEnabled()) { - LOG.debug("Starting Auditor Elector"); - } - } - - driver = MetadataDrivers.getBookieDriver( - URI.create(confByIndex(0).getMetadataServiceUri())); - driver.initialize( - confByIndex(0), - NullStatsLogger.INSTANCE); - } - - @After - @Override - public void tearDown() throws Exception { - if (null != driver) { - driver.close(); - } - - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - super.tearDown(); - } - - /** - * test that the periodic checking will detect corruptions in - * the bookie entry log. - */ - @Test - public void testEntryLogCorruption() throws Exception { - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - underReplicationManager.disableLedgerReplication(); - - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - long ledgerId = lh.getId(); - for (int i = 0; i < 100; i++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - - BookieAccessor.forceFlush((BookieImpl) serverByIndex(0).getBookie()); - - - File ledgerDir = confByIndex(0).getLedgerDirs()[0]; - ledgerDir = BookieImpl.getCurrentDirectory(ledgerDir); - // corrupt of entryLogs - File[] entryLogs = ledgerDir.listFiles(new FilenameFilter() { - public boolean accept(File dir, String name) { - return name.endsWith(".log"); - } - }); - ByteBuffer junk = ByteBuffer.allocate(1024 * 1024); - for (File f : entryLogs) { - FileOutputStream out = new FileOutputStream(f); - out.getChannel().write(junk); - out.close(); - } - restartBookies(); // restart to clear read buffers - - underReplicationManager.enableLedgerReplication(); - long underReplicatedLedger = -1; - for (int i = 0; i < 10; i++) { - underReplicatedLedger = underReplicationManager.pollLedgerToRereplicate(); - if (underReplicatedLedger != -1) { - break; - } - Thread.sleep(CHECK_INTERVAL * 1000); - } - assertEquals("Ledger should be under replicated", ledgerId, underReplicatedLedger); - underReplicationManager.close(); - } - - /** - * test that the period checker will detect corruptions in - * the bookie index files. - */ - @Test - public void testIndexCorruption() throws Exception { - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - - LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - long ledgerToCorrupt = lh.getId(); - for (int i = 0; i < 100; i++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - - // push ledgerToCorrupt out of page cache (bookie is configured to only use 1 page) - lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - for (int i = 0; i < 100; i++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - - BookieAccessor.forceFlush((BookieImpl) serverByIndex(0).getBookie()); - - File ledgerDir = confByIndex(0).getLedgerDirs()[0]; - ledgerDir = BookieImpl.getCurrentDirectory(ledgerDir); - - // corrupt of entryLogs - File index = new File(ledgerDir, IndexPersistenceMgr.getLedgerName(ledgerToCorrupt)); - LOG.info("file to corrupt{}" , index); - ByteBuffer junk = ByteBuffer.allocate(1024 * 1024); - FileOutputStream out = new FileOutputStream(index); - out.getChannel().write(junk); - out.close(); - - long underReplicatedLedger = -1; - for (int i = 0; i < 15; i++) { - underReplicatedLedger = underReplicationManager.pollLedgerToRereplicate(); - if (underReplicatedLedger != -1) { - break; - } - Thread.sleep(CHECK_INTERVAL * 1000); - } - assertEquals("Ledger should be under replicated", ledgerToCorrupt, underReplicatedLedger); - underReplicationManager.close(); - } - - /** - * Test that the period checker will not run when auto replication has been disabled. - */ - @Test - public void testPeriodicCheckWhenDisabled() throws Exception { - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - final LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - final int numLedgers = 10; - final int numMsgs = 2; - final CountDownLatch completeLatch = new CountDownLatch(numMsgs * numLedgers); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - - List lhs = new ArrayList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - lhs.add(lh); - for (int j = 0; j < 2; j++) { - lh.asyncAddEntry("testdata".getBytes(), new AddCallback() { - public void addComplete(int rc2, LedgerHandle lh, long entryId, Object ctx) { - if (rc.compareAndSet(BKException.Code.OK, rc2)) { - LOG.info("Failed to add entry : {}", BKException.getMessage(rc2)); - } - completeLatch.countDown(); - } - }, null); - } - } - completeLatch.await(); - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - - for (LedgerHandle lh : lhs) { - lh.close(); - } - - underReplicationManager.disableLedgerReplication(); - - final AtomicInteger numReads = new AtomicInteger(0); - ServerConfiguration conf = killBookie(0); - - Bookie deadBookie = new TestBookieImpl(conf) { - @Override - public ByteBuf readEntry(long ledgerId, long entryId) - throws IOException, NoLedgerException { - // we want to disable during checking - numReads.incrementAndGet(); - throw new IOException("Fake I/O exception"); - } - }; - startAndAddBookie(conf, deadBookie); - - Thread.sleep(CHECK_INTERVAL * 2000); - assertEquals("Nothing should have tried to read", 0, numReads.get()); - underReplicationManager.enableLedgerReplication(); - Thread.sleep(CHECK_INTERVAL * 2000); // give it time to run - - underReplicationManager.disableLedgerReplication(); - // give it time to stop, from this point nothing new should be marked - Thread.sleep(CHECK_INTERVAL * 2000); - - int numUnderreplicated = 0; - long underReplicatedLedger = -1; - do { - underReplicatedLedger = underReplicationManager.pollLedgerToRereplicate(); - if (underReplicatedLedger == -1) { - break; - } - numUnderreplicated++; - - underReplicationManager.markLedgerReplicated(underReplicatedLedger); - } while (underReplicatedLedger != -1); - - Thread.sleep(CHECK_INTERVAL * 2000); // give a chance to run again (it shouldn't, it's disabled) - - // ensure that nothing is marked as underreplicated - underReplicatedLedger = underReplicationManager.pollLedgerToRereplicate(); - assertEquals("There should be no underreplicated ledgers", -1, underReplicatedLedger); - - LOG.info("{} of {} ledgers underreplicated", numUnderreplicated, numUnderreplicated); - assertTrue("All should be underreplicated", - numUnderreplicated <= numLedgers && numUnderreplicated > 0); - } - - /** - * Test that the period check will succeed if a ledger is deleted midway. - */ - @Test - public void testPeriodicCheckWhenLedgerDeleted() throws Exception { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - try (final Auditor auditor = new Auditor( - BookieImpl.getBookieId(confByIndex(0)).toString(), - confByIndex(0), NullStatsLogger.INSTANCE)) { - final AtomicBoolean exceptionCaught = new AtomicBoolean(false); - final CountDownLatch latch = new CountDownLatch(1); - Thread t = new Thread() { - public void run() { - try { - latch.countDown(); - for (int i = 0; i < numLedgers; i++) { - ((AuditorCheckAllLedgersTask) auditor.auditorCheckAllLedgersTask).checkAllLedgers(); - } - } catch (Exception e) { - LOG.error("Caught exception while checking all ledgers", e); - exceptionCaught.set(true); - } - } - }; - t.start(); - latch.await(); - for (Long id : ids) { - bkc.deleteLedger(id); - } - t.join(); - assertFalse("Shouldn't have thrown exception", exceptionCaught.get()); - } - } - - @Test - public void testGetLedgerFromZookeeperThrottled() throws Exception { - final int numberLedgers = 30; - - // write ledgers into bookkeeper cluster - try { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - for (int i = 0; i < numberLedgers; ++i) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - for (int j = 0; j < 5; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - } catch (InterruptedException | BKException e) { - LOG.error("Failed to shutdown auditor elector or write data to ledgers ", e); - fail(); - } - - // create auditor and call `checkAllLedgers` - ServerConfiguration configuration = confByIndex(0); - configuration.setAuditorMaxNumberOfConcurrentOpenLedgerOperations(10); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - Counter numLedgersChecked = statsLogger - .getCounter(ReplicationStats.NUM_LEDGERS_CHECKED); - Auditor auditor = new Auditor(BookieImpl.getBookieId(configuration).toString(), - configuration, statsLogger); - - try { - ((AuditorCheckAllLedgersTask) auditor.auditorCheckAllLedgersTask).checkAllLedgers(); - assertEquals("NUM_LEDGERS_CHECKED", numberLedgers, (long) numLedgersChecked.get()); - } catch (Exception e) { - LOG.error("Caught exception while checking all ledgers ", e); - fail(); - } - } - - @Test - public void testInitialDelayOfCheckAllLedgers() throws Exception { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - validateInitialDelayOfCheckAllLedgers(urm, -1, 1000, servConf, bkc); - validateInitialDelayOfCheckAllLedgers(urm, 999, 1000, servConf, bkc); - validateInitialDelayOfCheckAllLedgers(urm, 1001, 1000, servConf, bkc); - } - - void validateInitialDelayOfCheckAllLedgers(LedgerUnderreplicationManager urm, long timeSinceLastExecutedInSecs, - long auditorPeriodicCheckInterval, ServerConfiguration servConf, BookKeeper bkc) - throws UnavailableException, UnknownHostException, InterruptedException { - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - TestOpStatsLogger checkAllLedgersStatsLogger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.CHECK_ALL_LEDGERS_TIME); - servConf.setAuditorPeriodicCheckInterval(auditorPeriodicCheckInterval); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(0); - servConf.setAuditorPeriodicBookieCheckInterval(0); - - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, bkc, false, - statsLogger, null); - CountDownLatch latch = auditor.getLatch(); - assertEquals("CHECK_ALL_LEDGERS_TIME SuccessCount", 0, checkAllLedgersStatsLogger.getSuccessCount()); - long curTimeBeforeStart = System.currentTimeMillis(); - long checkAllLedgersCTime = -1; - long initialDelayInMsecs = -1; - long nextExpectedCheckAllLedgersExecutionTime = -1; - long bufferTimeInMsecs = 12000L; - if (timeSinceLastExecutedInSecs == -1) { - /* - * if we are setting checkAllLedgersCTime to -1, it means that - * checkAllLedgers hasn't run before. So initialDelay for - * checkAllLedgers should be 0. - */ - checkAllLedgersCTime = -1; - initialDelayInMsecs = 0; - } else { - checkAllLedgersCTime = curTimeBeforeStart - timeSinceLastExecutedInSecs * 1000L; - initialDelayInMsecs = timeSinceLastExecutedInSecs > auditorPeriodicCheckInterval ? 0 - : (auditorPeriodicCheckInterval - timeSinceLastExecutedInSecs) * 1000L; - } - /* - * next checkAllLedgers should happen atleast after - * nextExpectedCheckAllLedgersExecutionTime. - */ - nextExpectedCheckAllLedgersExecutionTime = curTimeBeforeStart + initialDelayInMsecs; - - urm.setCheckAllLedgersCTime(checkAllLedgersCTime); - auditor.start(); - /* - * since auditorPeriodicCheckInterval are higher values (in the order of - * 100s of seconds), its ok bufferTimeInMsecs to be ` 10 secs. - */ - assertTrue("checkAllLedgers should have executed with initialDelay " + initialDelayInMsecs, - latch.await(initialDelayInMsecs + bufferTimeInMsecs, TimeUnit.MILLISECONDS)); - for (int i = 0; i < 10; i++) { - Thread.sleep(100); - if (checkAllLedgersStatsLogger.getSuccessCount() >= 1) { - break; - } - } - assertEquals("CHECK_ALL_LEDGERS_TIME SuccessCount", 1, checkAllLedgersStatsLogger.getSuccessCount()); - long currentCheckAllLedgersCTime = urm.getCheckAllLedgersCTime(); - assertTrue( - "currentCheckAllLedgersCTime: " + currentCheckAllLedgersCTime - + " should be greater than nextExpectedCheckAllLedgersExecutionTime: " - + nextExpectedCheckAllLedgersExecutionTime, - currentCheckAllLedgersCTime > nextExpectedCheckAllLedgersExecutionTime); - assertTrue( - "currentCheckAllLedgersCTime: " + currentCheckAllLedgersCTime - + " should be lesser than nextExpectedCheckAllLedgersExecutionTime+bufferTimeInMsecs: " - + (nextExpectedCheckAllLedgersExecutionTime + bufferTimeInMsecs), - currentCheckAllLedgersCTime < (nextExpectedCheckAllLedgersExecutionTime + bufferTimeInMsecs)); - auditor.close(); - } - - @Test - public void testInitialDelayOfPlacementPolicyCheck() throws Exception { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - validateInitialDelayOfPlacementPolicyCheck(urm, -1, 1000, servConf, bkc); - validateInitialDelayOfPlacementPolicyCheck(urm, 999, 1000, servConf, bkc); - validateInitialDelayOfPlacementPolicyCheck(urm, 1001, 1000, servConf, bkc); - } - - void validateInitialDelayOfPlacementPolicyCheck(LedgerUnderreplicationManager urm, long timeSinceLastExecutedInSecs, - long auditorPeriodicPlacementPolicyCheckInterval, ServerConfiguration servConf, BookKeeper bkc) - throws UnavailableException, UnknownHostException, InterruptedException { - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - TestOpStatsLogger placementPolicyCheckStatsLogger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.PLACEMENT_POLICY_CHECK_TIME); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(auditorPeriodicPlacementPolicyCheckInterval); - servConf.setAuditorPeriodicCheckInterval(0); - servConf.setAuditorPeriodicBookieCheckInterval(0); - - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, bkc, false, - statsLogger, null); - CountDownLatch latch = auditor.getLatch(); - assertEquals("PLACEMENT_POLICY_CHECK_TIME SuccessCount", 0, placementPolicyCheckStatsLogger.getSuccessCount()); - long curTimeBeforeStart = System.currentTimeMillis(); - long placementPolicyCheckCTime = -1; - long initialDelayInMsecs = -1; - long nextExpectedPlacementPolicyCheckExecutionTime = -1; - long bufferTimeInMsecs = 20000L; - if (timeSinceLastExecutedInSecs == -1) { - /* - * if we are setting placementPolicyCheckCTime to -1, it means that - * placementPolicyCheck hasn't run before. So initialDelay for - * placementPolicyCheck should be 0. - */ - placementPolicyCheckCTime = -1; - initialDelayInMsecs = 0; - } else { - placementPolicyCheckCTime = curTimeBeforeStart - timeSinceLastExecutedInSecs * 1000L; - initialDelayInMsecs = timeSinceLastExecutedInSecs > auditorPeriodicPlacementPolicyCheckInterval ? 0 - : (auditorPeriodicPlacementPolicyCheckInterval - timeSinceLastExecutedInSecs) * 1000L; - } - /* - * next placementPolicyCheck should happen atleast after - * nextExpectedPlacementPolicyCheckExecutionTime. - */ - nextExpectedPlacementPolicyCheckExecutionTime = curTimeBeforeStart + initialDelayInMsecs; - - urm.setPlacementPolicyCheckCTime(placementPolicyCheckCTime); - auditor.start(); - /* - * since auditorPeriodicPlacementPolicyCheckInterval are higher values (in the - * order of 100s of seconds), its ok bufferTimeInMsecs to be ` 20 secs. - */ - assertTrue("placementPolicyCheck should have executed with initialDelay " + initialDelayInMsecs, - latch.await(initialDelayInMsecs + bufferTimeInMsecs, TimeUnit.MILLISECONDS)); - for (int i = 0; i < 20; i++) { - Thread.sleep(100); - if (placementPolicyCheckStatsLogger.getSuccessCount() >= 1) { - break; - } - } - assertEquals("PLACEMENT_POLICY_CHECK_TIME SuccessCount", 1, placementPolicyCheckStatsLogger.getSuccessCount()); - long currentPlacementPolicyCheckCTime = urm.getPlacementPolicyCheckCTime(); - assertTrue( - "currentPlacementPolicyCheckCTime: " + currentPlacementPolicyCheckCTime - + " should be greater than nextExpectedPlacementPolicyCheckExecutionTime: " - + nextExpectedPlacementPolicyCheckExecutionTime, - currentPlacementPolicyCheckCTime > nextExpectedPlacementPolicyCheckExecutionTime); - assertTrue( - "currentPlacementPolicyCheckCTime: " + currentPlacementPolicyCheckCTime - + " should be lesser than nextExpectedPlacementPolicyCheckExecutionTime+bufferTimeInMsecs: " - + (nextExpectedPlacementPolicyCheckExecutionTime + bufferTimeInMsecs), - currentPlacementPolicyCheckCTime < (nextExpectedPlacementPolicyCheckExecutionTime + bufferTimeInMsecs)); - auditor.close(); - } - - @Test - public void testInitialDelayOfReplicasCheck() throws Exception { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - LedgerHandle lh = bkc.createLedger(3, 2, DigestType.CRC32, "passwd".getBytes()); - for (int j = 0; j < 5; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - - long ledgerId = 100000L; - lh = bkc.createLedgerAdv(ledgerId, 3, 2, 2, DigestType.CRC32, "passwd".getBytes(), null); - lh.close(); - - ledgerId = 100001234L; - lh = bkc.createLedgerAdv(ledgerId, 3, 3, 2, DigestType.CRC32, "passwd".getBytes(), null); - for (int j = 0; j < 4; j++) { - lh.addEntry(j, "testdata".getBytes()); - } - lh.close(); - - ledgerId = 991234L; - lh = bkc.createLedgerAdv(ledgerId, 3, 2, 2, DigestType.CRC32, "passwd".getBytes(), null); - lh.addEntry(0, "testdata".getBytes()); - lh.close(); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - validateInitialDelayOfReplicasCheck(urm, -1, 1000, servConf, bkc); - validateInitialDelayOfReplicasCheck(urm, 999, 1000, servConf, bkc); - validateInitialDelayOfReplicasCheck(urm, 1001, 1000, servConf, bkc); - } - - void validateInitialDelayOfReplicasCheck(LedgerUnderreplicationManager urm, long timeSinceLastExecutedInSecs, - long auditorPeriodicReplicasCheckInterval, ServerConfiguration servConf, BookKeeper bkc) - throws UnavailableException, UnknownHostException, InterruptedException { - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - TestOpStatsLogger replicasCheckStatsLogger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.REPLICAS_CHECK_TIME); - servConf.setAuditorPeriodicReplicasCheckInterval(auditorPeriodicReplicasCheckInterval); - servConf.setAuditorPeriodicCheckInterval(0); - servConf.setAuditorPeriodicBookieCheckInterval(0); - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, bkc, false, - statsLogger, null); - CountDownLatch latch = auditor.getLatch(); - assertEquals("REPLICAS_CHECK_TIME SuccessCount", 0, replicasCheckStatsLogger.getSuccessCount()); - long curTimeBeforeStart = System.currentTimeMillis(); - long replicasCheckCTime = -1; - long initialDelayInMsecs = -1; - long nextExpectedReplicasCheckExecutionTime = -1; - long bufferTimeInMsecs = 20000L; - if (timeSinceLastExecutedInSecs == -1) { - /* - * if we are setting replicasCheckCTime to -1, it means that - * replicasCheck hasn't run before. So initialDelay for - * replicasCheck should be 0. - */ - replicasCheckCTime = -1; - initialDelayInMsecs = 0; - } else { - replicasCheckCTime = curTimeBeforeStart - timeSinceLastExecutedInSecs * 1000L; - initialDelayInMsecs = timeSinceLastExecutedInSecs > auditorPeriodicReplicasCheckInterval ? 0 - : (auditorPeriodicReplicasCheckInterval - timeSinceLastExecutedInSecs) * 1000L; - } - /* - * next replicasCheck should happen atleast after - * nextExpectedReplicasCheckExecutionTime. - */ - nextExpectedReplicasCheckExecutionTime = curTimeBeforeStart + initialDelayInMsecs; - - urm.setReplicasCheckCTime(replicasCheckCTime); - auditor.start(); - /* - * since auditorPeriodicReplicasCheckInterval are higher values (in the - * order of 100s of seconds), its ok bufferTimeInMsecs to be ` 20 secs. - */ - assertTrue("replicasCheck should have executed with initialDelay " + initialDelayInMsecs, - latch.await(initialDelayInMsecs + bufferTimeInMsecs, TimeUnit.MILLISECONDS)); - for (int i = 0; i < 20; i++) { - Thread.sleep(100); - if (replicasCheckStatsLogger.getSuccessCount() >= 1) { - break; - } - } - assertEquals("REPLICAS_CHECK_TIME SuccessCount", 1, replicasCheckStatsLogger.getSuccessCount()); - long currentReplicasCheckCTime = urm.getReplicasCheckCTime(); - assertTrue( - "currentReplicasCheckCTime: " + currentReplicasCheckCTime - + " should be greater than nextExpectedReplicasCheckExecutionTime: " - + nextExpectedReplicasCheckExecutionTime, - currentReplicasCheckCTime > nextExpectedReplicasCheckExecutionTime); - assertTrue( - "currentReplicasCheckCTime: " + currentReplicasCheckCTime - + " should be lesser than nextExpectedReplicasCheckExecutionTime+bufferTimeInMsecs: " - + (nextExpectedReplicasCheckExecutionTime + bufferTimeInMsecs), - currentReplicasCheckCTime < (nextExpectedReplicasCheckExecutionTime + bufferTimeInMsecs)); - auditor.close(); - } - - @Test - public void testDelayBookieAuditOfCheckAllLedgers() throws Exception { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - Counter numBookieAuditsDelayed = - statsLogger.getCounter(ReplicationStats.NUM_BOOKIE_AUDITS_DELAYED); - TestOpStatsLogger underReplicatedLedgerTotalSizeStatsLogger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.UNDER_REPLICATED_LEDGERS_TOTAL_SIZE); - Counter numSkippingCheckTaskTimes = - statsLogger.getCounter(ReplicationStats.NUM_SKIPPING_CHECK_TASK_TIMES); - - servConf.setAuditorPeriodicCheckInterval(1); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(0); - servConf.setAuditorPeriodicBookieCheckInterval(Long.MAX_VALUE); - - urm.setLostBookieRecoveryDelay(Integer.MAX_VALUE); - - AtomicBoolean canRun = new AtomicBoolean(false); - - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, bkc, - false, statsLogger, canRun); - final CountDownLatch latch = auditor.getLatch(); - - auditor.start(); - - killBookie(addressByIndex(0)); - - Awaitility.await().untilAsserted(() -> assertEquals(1, (long) numBookieAuditsDelayed.get())); - final Future auditTask = auditor.auditTask; - assertTrue(auditTask != null && !auditTask.isDone()); - assertEquals("NUM_SKIPPING_CHECK_TASK_TIMES", 0, (long) numSkippingCheckTaskTimes.get()); - - canRun.set(true); - - assertTrue(latch.await(10, TimeUnit.SECONDS)); - assertTrue(auditor.auditTask.equals(auditTask) - && auditor.auditTask != null && !auditor.auditTask.isDone()); - // wrong num is numLedgers, right num is 0 - assertEquals("UNDER_REPLICATED_LEDGERS_TOTAL_SIZE", - 0, - underReplicatedLedgerTotalSizeStatsLogger.getSuccessCount()); - assertTrue("NUM_SKIPPING_CHECK_TASK_TIMES", numSkippingCheckTaskTimes.get() > 0); - - auditor.close(); - } - - @Test - public void testDelayBookieAuditOfPlacementPolicy() throws Exception { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - Counter numBookieAuditsDelayed = - statsLogger.getCounter(ReplicationStats.NUM_BOOKIE_AUDITS_DELAYED); - TestOpStatsLogger placementPolicyCheckTime = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.PLACEMENT_POLICY_CHECK_TIME); - Counter numSkippingCheckTaskTimes = - statsLogger.getCounter(ReplicationStats.NUM_SKIPPING_CHECK_TASK_TIMES); - - servConf.setAuditorPeriodicCheckInterval(0); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(1); - servConf.setAuditorPeriodicBookieCheckInterval(Long.MAX_VALUE); - - urm.setLostBookieRecoveryDelay(Integer.MAX_VALUE); - - AtomicBoolean canRun = new AtomicBoolean(false); - - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, bkc, - false, statsLogger, canRun); - final CountDownLatch latch = auditor.getLatch(); - - auditor.start(); - - killBookie(addressByIndex(0)); - - Awaitility.await().untilAsserted(() -> assertEquals(1, (long) numBookieAuditsDelayed.get())); - final Future auditTask = auditor.auditTask; - assertTrue(auditTask != null && !auditTask.isDone()); - assertEquals("PLACEMENT_POLICY_CHECK_TIME", 0, placementPolicyCheckTime.getSuccessCount()); - assertEquals("NUM_SKIPPING_CHECK_TASK_TIMES", 0, (long) numSkippingCheckTaskTimes.get()); - - canRun.set(true); - - assertTrue(latch.await(10, TimeUnit.SECONDS)); - assertTrue(auditor.auditTask.equals(auditTask) - && auditor.auditTask != null && !auditor.auditTask.isDone()); - // wrong successCount is > 0, right successCount is = 0 - assertEquals("PLACEMENT_POLICY_CHECK_TIME", 0, placementPolicyCheckTime.getSuccessCount()); - assertTrue("NUM_SKIPPING_CHECK_TASK_TIMES", numSkippingCheckTaskTimes.get() > 0); - - auditor.close(); - } - - @Test - public void testDelayBookieAuditOfReplicasCheck() throws Exception { - for (AuditorElector e : auditorElectors.values()) { - e.shutdown(); - } - - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - Counter numBookieAuditsDelayed = - statsLogger.getCounter(ReplicationStats.NUM_BOOKIE_AUDITS_DELAYED); - TestOpStatsLogger replicasCheckTime = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.REPLICAS_CHECK_TIME); - Counter numSkippingCheckTaskTimes = - statsLogger.getCounter(ReplicationStats.NUM_SKIPPING_CHECK_TASK_TIMES); - - servConf.setAuditorPeriodicCheckInterval(0); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(0); - servConf.setAuditorPeriodicBookieCheckInterval(Long.MAX_VALUE); - servConf.setAuditorPeriodicReplicasCheckInterval(1); - - urm.setLostBookieRecoveryDelay(Integer.MAX_VALUE); - - AtomicBoolean canRun = new AtomicBoolean(false); - - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, bkc, - false, statsLogger, canRun); - final CountDownLatch latch = auditor.getLatch(); - - auditor.start(); - - killBookie(addressByIndex(0)); - - Awaitility.await().untilAsserted(() -> assertEquals(1, (long) numBookieAuditsDelayed.get())); - final Future auditTask = auditor.auditTask; - assertTrue(auditTask != null && !auditTask.isDone()); - assertEquals("REPLICAS_CHECK_TIME", 0, replicasCheckTime.getSuccessCount()); - assertEquals("NUM_SKIPPING_CHECK_TASK_TIMES", 0, (long) numSkippingCheckTaskTimes.get()); - - canRun.set(true); - - assertTrue(latch.await(10, TimeUnit.SECONDS)); - assertTrue(auditor.auditTask.equals(auditTask) - && auditor.auditTask != null && !auditor.auditTask.isDone()); - // wrong successCount is > 0, right successCount is = 0 - assertEquals("REPLICAS_CHECK_TIME", 0, replicasCheckTime.getSuccessCount()); - assertTrue("NUM_SKIPPING_CHECK_TASK_TIMES", numSkippingCheckTaskTimes.get() > 0); - - auditor.close(); - } - - static class TestAuditor extends Auditor { - - final AtomicReference latchRef = new AtomicReference(new CountDownLatch(1)); - - public TestAuditor(String bookieIdentifier, ServerConfiguration conf, BookKeeper bkc, boolean ownBkc, - StatsLogger statsLogger, AtomicBoolean exceptedRun) throws UnavailableException { - super(bookieIdentifier, conf, bkc, ownBkc, statsLogger); - renewAuditorTestWrapperTask(exceptedRun); - } - - public TestAuditor(String bookieIdentifier, ServerConfiguration conf, BookKeeper bkc, boolean ownBkc, - BookKeeperAdmin bkadmin, boolean ownadmin, StatsLogger statsLogger, - AtomicBoolean exceptedRun) throws UnavailableException { - super(bookieIdentifier, conf, bkc, ownBkc, bkadmin, ownadmin, statsLogger); - renewAuditorTestWrapperTask(exceptedRun); - } - - public TestAuditor(final String bookieIdentifier, ServerConfiguration conf, StatsLogger statsLogger, - AtomicBoolean exceptedRun) - throws UnavailableException { - super(bookieIdentifier, conf, statsLogger); - renewAuditorTestWrapperTask(exceptedRun); - } - - private void renewAuditorTestWrapperTask(AtomicBoolean exceptedRun) { - super.auditorCheckAllLedgersTask = - new AuditorTestWrapperTask(super.auditorCheckAllLedgersTask, latchRef, exceptedRun); - super.auditorPlacementPolicyCheckTask = - new AuditorTestWrapperTask(super.auditorPlacementPolicyCheckTask, latchRef, exceptedRun); - super.auditorReplicasCheckTask = - new AuditorTestWrapperTask(super.auditorReplicasCheckTask, latchRef, exceptedRun); - } - - CountDownLatch getLatch() { - return latchRef.get(); - } - - void setLatch(CountDownLatch latch) { - latchRef.set(latch); - } - - private static class AuditorTestWrapperTask extends AuditorTask { - private final AuditorTask innerTask; - private final AtomicReference latchRef; - private final AtomicBoolean exceptedRun; - - AuditorTestWrapperTask(AuditorTask innerTask, - AtomicReference latchRef, - AtomicBoolean exceptedRun) { - super(null, null, null, null, null, - null, null); - this.innerTask = innerTask; - this.latchRef = latchRef; - this.exceptedRun = exceptedRun; - } - - @Override - protected void runTask() { - if (exceptedRun == null || exceptedRun.get()) { - innerTask.runTask(); - latchRef.get().countDown(); - } - } - - @Override - public void shutdown() { - innerTask.shutdown(); - } - } - } - - private BookieId replaceBookieWithWriteFailingBookie(LedgerHandle lh) throws Exception { - int bookieIdx = -1; - Long entryId = lh.getLedgerMetadata().getAllEnsembles().firstKey(); - List curEnsemble = lh.getLedgerMetadata().getAllEnsembles().get(entryId); - - // Identify a bookie in the current ledger ensemble to be replaced - BookieId replacedBookie = null; - for (int i = 0; i < numBookies; i++) { - if (curEnsemble.contains(addressByIndex(i))) { - bookieIdx = i; - replacedBookie = addressByIndex(i); - break; - } - } - assertNotEquals("Couldn't find ensemble bookie in bookie list", -1, bookieIdx); - - LOG.info("Killing bookie " + addressByIndex(bookieIdx)); - ServerConfiguration conf = killBookie(bookieIdx); - Bookie writeFailingBookie = new TestBookieImpl(conf) { - @Override - public void addEntry(ByteBuf entry, boolean ackBeforeSync, WriteCallback cb, - Object ctx, byte[] masterKey) - throws IOException, BookieException { - try { - LOG.info("Failing write to entry "); - // sleep a bit so that writes to other bookies succeed before - // the client hears about the failure on this bookie. If the - // client gets ack-quorum number of acks first, it won't care - // about any failures and won't reform the ensemble. - Thread.sleep(100); - throw new IOException(); - } catch (InterruptedException ie) { - // ignore, only interrupted if shutting down, - // and an exception would spam the logs - Thread.currentThread().interrupt(); - } - } - }; - startAndAddBookie(conf, writeFailingBookie); - return replacedBookie; - } - - /* - * Validates that the periodic ledger check will fix entries with a failed write. - */ - @Test - public void testFailedWriteRecovery() throws Exception { - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - underReplicationManager.disableLedgerReplication(); - - LedgerHandle lh = bkc.createLedger(2, 2, 1, DigestType.CRC32, "passwd".getBytes()); - - // kill one of the bookies and replace it with one that rejects write; - // This way we get into the under replication state - BookieId replacedBookie = replaceBookieWithWriteFailingBookie(lh); - - // Write a few entries; this should cause under replication - byte[] data = "foobar".getBytes(); - data = "foobar".getBytes(); - lh.addEntry(data); - lh.addEntry(data); - lh.addEntry(data); - - lh.close(); - - // enable under replication detection and wait for it to report - // under replicated ledger - underReplicationManager.enableLedgerReplication(); - long underReplicatedLedger = -1; - for (int i = 0; i < 5; i++) { - underReplicatedLedger = underReplicationManager.pollLedgerToRereplicate(); - if (underReplicatedLedger != -1) { - break; - } - Thread.sleep(CHECK_INTERVAL * 1000); - } - assertEquals("Ledger should be under replicated", lh.getId(), underReplicatedLedger); - - // now start the replication workers - List l = new ArrayList(); - for (int i = 0; i < numBookies; i++) { - ReplicationWorker rw = new ReplicationWorker(confByIndex(i), NullStatsLogger.INSTANCE); - rw.start(); - l.add(rw); - } - underReplicationManager.close(); - - // Wait for ensemble to change after replication - Thread.sleep(3000); - for (ReplicationWorker rw : l) { - rw.shutdown(); - } - - // check that ensemble has changed and the bookie that rejected writes has - // been replaced in the ensemble - LedgerHandle newLh = bkc.openLedger(lh.getId(), DigestType.CRC32, "passwd".getBytes()); - for (Map.Entry> e : - newLh.getLedgerMetadata().getAllEnsembles().entrySet()) { - List ensemble = e.getValue(); - assertFalse("Ensemble hasn't been updated", ensemble.contains(replacedBookie)); - } - newLh.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTaskTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTaskTest.java deleted file mode 100644 index 6d951d71803..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTaskTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.junit.Assert.assertEquals; - -import java.util.LinkedList; -import java.util.List; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit test {@link AuditorPlacementPolicyCheckTask}. - */ -public class AuditorPlacementPolicyCheckTaskTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory - .getLogger(AuditorPlacementPolicyCheckTaskTest.class); - - private BookKeeperAdmin admin; - private LedgerManager ledgerManager; - private LedgerUnderreplicationManager ledgerUnderreplicationManager; - - public AuditorPlacementPolicyCheckTaskTest() { - super(3); - baseConf.setPageLimit(1); - baseConf.setAutoRecoveryDaemonEnabled(false); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - final BookKeeper bookKeeper = new BookKeeper(baseClientConf); - admin = new BookKeeperAdmin(bookKeeper, NullStatsLogger.INSTANCE, new ClientConfiguration(baseClientConf)); - LedgerManagerFactory ledgerManagerFactory = bookKeeper.getLedgerManagerFactory(); - ledgerManager = ledgerManagerFactory.newLedgerManager(); - ledgerUnderreplicationManager = ledgerManagerFactory.newLedgerUnderreplicationManager(); - } - - @Test - public void testPlacementPolicyCheck() throws BKException, InterruptedException { - - // 1. create ledgers - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - // 2. init auditorPlacementPolicyCheckTask - final TestStatsProvider statsProvider = new TestStatsProvider(); - final TestStatsProvider.TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - final AuditorStats auditorStats = new AuditorStats(statsLogger); - - AuditorPlacementPolicyCheckTask auditorPlacementPolicyCheckTask = new AuditorPlacementPolicyCheckTask( - baseConf, auditorStats, admin, ledgerManager, - ledgerUnderreplicationManager, null, (flag, throwable) -> flag.set(false)); - - // 3. placementPolicyCheck - auditorPlacementPolicyCheckTask.runTask(); - - // 4. verify - assertEquals("PLACEMENT_POLICY_CHECK_TIME", 1, ((TestStatsProvider.TestOpStatsLogger) - statsLogger.getOpStatsLogger(ReplicationStats.PLACEMENT_POLICY_CHECK_TIME)).getSuccessCount()); - assertEquals("numOfClosedLedgersAuditedInPlacementPolicyCheck", - numLedgers, - auditorPlacementPolicyCheckTask.getNumOfClosedLedgersAuditedInPlacementPolicyCheck().get()); - assertEquals("numOfLedgersFoundNotAdheringInPlacementPolicyCheck", - numLedgers, - auditorPlacementPolicyCheckTask.getNumOfLedgersFoundNotAdheringInPlacementPolicyCheck().get()); - } - -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java deleted file mode 100644 index e14deb3fb59..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java +++ /dev/null @@ -1,854 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicyImpl.REPP_DNS_RESOLVER_CLASS; -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.net.URI; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.ZoneawareEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.BookieServiceInfo; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.exceptions.MetadataException; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.replication.AuditorPeriodicCheckTest.TestAuditor; -import org.apache.bookkeeper.replication.ReplicationException.CompatibilityException; -import org.apache.bookkeeper.replication.ReplicationException.UnavailableException; -import org.apache.bookkeeper.stats.Gauge; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.apache.commons.lang3.mutable.MutableObject; -import org.apache.zookeeper.KeeperException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Tests the logic of Auditor's PlacementPolicyCheck. - */ -public class AuditorPlacementPolicyCheckTest extends BookKeeperClusterTestCase { - private MetadataBookieDriver driver; - - public AuditorPlacementPolicyCheckTest() { - super(1); - baseConf.setPageLimit(1); // to make it easy to push ledger out of cache - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - StaticDNSResolver.reset(); - driver = MetadataDrivers.getBookieDriver(URI.create(confByIndex(0).getMetadataServiceUri())); - driver.initialize(confByIndex(0), NullStatsLogger.INSTANCE); - } - - @After - @Override - public void tearDown() throws Exception { - if (null != driver) { - driver.close(); - } - super.tearDown(); - } - - @Test - public void testPlacementPolicyCheckWithBookiesFromDifferentRacks() throws Exception { - int numOfBookies = 5; - List bookieAddresses = new ArrayList<>(); - BookieSocketAddress bookieAddress; - try (RegistrationManager regManager = driver.createRegistrationManager()) { - // all the numOfBookies (5) are going to be in different racks - for (int i = 0; i < numOfBookies; i++) { - bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181); - StaticDNSResolver.addNodeToRack(bookieAddress.getHostName(), "/rack" + (i)); - bookieAddresses.add(bookieAddress.toBookieId()); - regManager.registerBookie(bookieAddress.toBookieId(), false, BookieServiceInfo.EMPTY); - } - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - int ensembleSize = 5; - int writeQuorumSize = 4; - int ackQuorumSize = 2; - int minNumRacksPerWriteQuorumConfValue = 4; - Collections.shuffle(bookieAddresses); - - // closed ledger - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(1L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(1L, initMeta).get(); - - Collections.shuffle(bookieAddresses); - ensembleSize = 4; - // closed ledger with multiple segments - initMeta = LedgerMetadataBuilder.create() - .withId(2L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses.subList(0, 4)) - .newEnsembleEntry(20L, bookieAddresses.subList(1, 5)) - .newEnsembleEntry(60L, bookieAddresses.subList(0, 4)) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(2L, initMeta).get(); - - Collections.shuffle(bookieAddresses); - // non-closed ledger - initMeta = LedgerMetadataBuilder.create() - .withId(3L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses.subList(0, 4)) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(3L, initMeta).get(); - - Collections.shuffle(bookieAddresses); - // non-closed ledger with multiple segments - initMeta = LedgerMetadataBuilder.create() - .withId(4L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses.subList(0, 4)) - .newEnsembleEntry(20L, bookieAddresses.subList(1, 5)) - .newEnsembleEntry(60L, bookieAddresses.subList(0, 4)) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(4L, initMeta).get(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - setServerConfigPropertiesForRackPlacement(servConf); - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge ledgersNotAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY); - Gauge ledgersSoftlyAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY); - /* - * since all of the bookies are in different racks, there shouldn't be any ledger not adhering - * to placement policy. - */ - assertEquals("NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY guage value", 0, - ledgersNotAdheringToPlacementPolicyGuage.getSample()); - /* - * since all of the bookies are in different racks, there shouldn't be any ledger softly adhering - * to placement policy. - */ - assertEquals("NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY guage value", 0, - ledgersSoftlyAdheringToPlacementPolicyGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - } - - @Test - public void testPlacementPolicyCheckWithLedgersNotAdheringToPlacementPolicy() throws Exception { - int numOfBookies = 5; - int numOfLedgersNotAdheringToPlacementPolicy = 0; - List bookieAddresses = new ArrayList<>(); - try (RegistrationManager regManager = driver.createRegistrationManager()) { - for (int i = 0; i < numOfBookies; i++) { - BookieId bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181).toBookieId(); - bookieAddresses.add(bookieAddress); - regManager.registerBookie(bookieAddress, false, BookieServiceInfo.EMPTY); - } - } - - // only three racks - StaticDNSResolver.addNodeToRack("98.98.98.0", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.1", "/rack2"); - StaticDNSResolver.addNodeToRack("98.98.98.2", "/rack3"); - StaticDNSResolver.addNodeToRack("98.98.98.3", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.4", "/rack2"); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - int ensembleSize = 5; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - int minNumRacksPerWriteQuorumConfValue = 3; - - /* - * this closed ledger doesn't adhere to placement policy because there are only - * 3 racks, and the ensembleSize is 5. - */ - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(1L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(1L, initMeta).get(); - numOfLedgersNotAdheringToPlacementPolicy++; - - /* - * this is non-closed ledger, so it shouldn't count as ledger not - * adhering to placement policy - */ - initMeta = LedgerMetadataBuilder.create() - .withId(2L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(2L, initMeta).get(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - setServerConfigPropertiesForRackPlacement(servConf); - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge ledgersNotAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY guage value", - numOfLedgersNotAdheringToPlacementPolicy, ledgersNotAdheringToPlacementPolicyGuage.getSample()); - Gauge ledgersSoftlyAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY guage value", - 0, ledgersSoftlyAdheringToPlacementPolicyGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - } - - @Test - public void testPlacementPolicyCheckWithLedgersNotAdheringToPlacementPolicyAndNotMarkToUnderreplication() - throws Exception { - int numOfBookies = 5; - int numOfLedgersNotAdheringToPlacementPolicy = 0; - List bookieAddresses = new ArrayList<>(); - try (RegistrationManager regManager = driver.createRegistrationManager()) { - for (int i = 0; i < numOfBookies; i++) { - BookieId bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181).toBookieId(); - bookieAddresses.add(bookieAddress); - regManager.registerBookie(bookieAddress, false, BookieServiceInfo.EMPTY); - } - } - - // only three racks - StaticDNSResolver.addNodeToRack("98.98.98.0", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.1", "/rack2"); - StaticDNSResolver.addNodeToRack("98.98.98.2", "/rack3"); - StaticDNSResolver.addNodeToRack("98.98.98.3", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.4", "/rack2"); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - int ensembleSize = 5; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - int minNumRacksPerWriteQuorumConfValue = 3; - - /* - * this closed ledger doesn't adhere to placement policy because there are only - * 3 racks, and the ensembleSize is 5. - */ - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(1L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(1L, initMeta).get(); - numOfLedgersNotAdheringToPlacementPolicy++; - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - setServerConfigPropertiesForRackPlacement(servConf); - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge ledgersNotAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY guage value", - numOfLedgersNotAdheringToPlacementPolicy, ledgersNotAdheringToPlacementPolicyGuage.getSample()); - Gauge ledgersSoftlyAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY guage value", - 0, ledgersSoftlyAdheringToPlacementPolicyGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - LedgerUnderreplicationManager underreplicationManager = mFactory.newLedgerUnderreplicationManager(); - long unnderReplicateLedgerId = underreplicationManager.pollLedgerToRereplicate(); - assertEquals(unnderReplicateLedgerId, -1); - } - - @Test - public void testPlacementPolicyCheckWithLedgersNotAdheringToPlacementPolicyAndMarkToUnderreplication() - throws Exception { - int numOfBookies = 5; - int numOfLedgersNotAdheringToPlacementPolicy = 0; - List bookieAddresses = new ArrayList<>(); - try (RegistrationManager regManager = driver.createRegistrationManager()) { - for (int i = 0; i < numOfBookies; i++) { - BookieId bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181).toBookieId(); - bookieAddresses.add(bookieAddress); - regManager.registerBookie(bookieAddress, false, BookieServiceInfo.EMPTY); - } - } - - // only three racks - StaticDNSResolver.addNodeToRack("98.98.98.0", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.1", "/rack2"); - StaticDNSResolver.addNodeToRack("98.98.98.2", "/rack3"); - StaticDNSResolver.addNodeToRack("98.98.98.3", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.4", "/rack2"); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - int ensembleSize = 5; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - int minNumRacksPerWriteQuorumConfValue = 3; - - /* - * this closed ledger doesn't adhere to placement policy because there are only - * 3 racks, and the ensembleSize is 5. - */ - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(1L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(1L, initMeta).get(); - numOfLedgersNotAdheringToPlacementPolicy++; - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - servConf.setRepairedPlacementPolicyNotAdheringBookieEnable(true); - setServerConfigPropertiesForRackPlacement(servConf); - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge ledgersNotAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY guage value", - numOfLedgersNotAdheringToPlacementPolicy, ledgersNotAdheringToPlacementPolicyGuage.getSample()); - Gauge ledgersSoftlyAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY guage value", - 0, ledgersSoftlyAdheringToPlacementPolicyGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - LedgerUnderreplicationManager underreplicationManager = mFactory.newLedgerUnderreplicationManager(); - long unnderReplicateLedgerId = underreplicationManager.pollLedgerToRereplicate(); - assertEquals(unnderReplicateLedgerId, 1L); - } - - @Test - public void testPlacementPolicyCheckForURLedgersElapsedRecoveryGracePeriod() throws Exception { - testPlacementPolicyCheckWithURLedgers(true); - } - - @Test - public void testPlacementPolicyCheckForURLedgersNotElapsedRecoveryGracePeriod() throws Exception { - testPlacementPolicyCheckWithURLedgers(false); - } - - public void testPlacementPolicyCheckWithURLedgers(boolean timeElapsed) throws Exception { - int numOfBookies = 4; - /* - * in timeElapsed=true scenario, set some low value, otherwise set some - * highValue. - */ - int underreplicatedLedgerRecoveryGracePeriod = timeElapsed ? 1 : 1000; - int numOfURLedgersElapsedRecoveryGracePeriod = 0; - List bookieAddresses = new ArrayList(); - try (RegistrationManager regManager = driver.createRegistrationManager()) { - for (int i = 0; i < numOfBookies; i++) { - BookieId bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181).toBookieId(); - bookieAddresses.add(bookieAddress); - regManager.registerBookie(bookieAddress, false, BookieServiceInfo.EMPTY); - } - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - LedgerUnderreplicationManager underreplicationManager = mFactory.newLedgerUnderreplicationManager(); - int ensembleSize = 4; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - - long ledgerId1 = 1L; - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(ledgerId1) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(ledgerId1, initMeta).get(); - underreplicationManager.markLedgerUnderreplicated(ledgerId1, bookieAddresses.get(0).toString()); - if (timeElapsed) { - numOfURLedgersElapsedRecoveryGracePeriod++; - } - - /* - * this is non-closed ledger, it should also be reported as - * URLedgersElapsedRecoveryGracePeriod - */ - ensembleSize = 3; - long ledgerId2 = 21234561L; - initMeta = LedgerMetadataBuilder.create() - .withId(ledgerId2) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, - Arrays.asList(bookieAddresses.get(0), bookieAddresses.get(1), bookieAddresses.get(2))) - .newEnsembleEntry(100L, - Arrays.asList(bookieAddresses.get(3), bookieAddresses.get(1), bookieAddresses.get(2))) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(ledgerId2, initMeta).get(); - underreplicationManager.markLedgerUnderreplicated(ledgerId2, bookieAddresses.get(0).toString()); - if (timeElapsed) { - numOfURLedgersElapsedRecoveryGracePeriod++; - } - - /* - * this ledger is not marked underreplicated. - */ - long ledgerId3 = 31234561L; - initMeta = LedgerMetadataBuilder.create() - .withId(ledgerId3) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, - Arrays.asList(bookieAddresses.get(1), bookieAddresses.get(2), bookieAddresses.get(3))) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(ledgerId3, initMeta).get(); - - if (timeElapsed) { - /* - * in timeelapsed scenario, by waiting for - * underreplicatedLedgerRecoveryGracePeriod, recovery time must be - * elapsed. - */ - Thread.sleep((underreplicatedLedgerRecoveryGracePeriod + 1) * 1000); - } else { - /* - * in timeElapsed=false scenario, since - * underreplicatedLedgerRecoveryGracePeriod is set to some high - * value, there is no value in waiting. So just wait for some time - * and make sure urledgers are not reported as recoverytime elapsed - * urledgers. - */ - Thread.sleep(5000); - } - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setUnderreplicatedLedgerRecoveryGracePeriod(underreplicatedLedgerRecoveryGracePeriod); - setServerConfigPropertiesForRackPlacement(servConf); - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge underreplicatedLedgersElapsedRecoveryGracePeriodGuage = statsLogger - .getGauge(ReplicationStats.NUM_UNDERREPLICATED_LEDGERS_ELAPSED_RECOVERY_GRACE_PERIOD); - assertEquals("NUM_UNDERREPLICATED_LEDGERS_ELAPSED_RECOVERY_GRACE_PERIOD guage value", - numOfURLedgersElapsedRecoveryGracePeriod, - underreplicatedLedgersElapsedRecoveryGracePeriodGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - } - - @Test - public void testPlacementPolicyCheckWithLedgersNotAdheringToPolicyWithMultipleSegments() throws Exception { - int numOfBookies = 7; - int numOfLedgersNotAdheringToPlacementPolicy = 0; - List bookieAddresses = new ArrayList<>(); - try (RegistrationManager regManager = driver.createRegistrationManager()) { - for (int i = 0; i < numOfBookies; i++) { - BookieId bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181).toBookieId(); - bookieAddresses.add(bookieAddress); - regManager.registerBookie(bookieAddress, false, BookieServiceInfo.EMPTY); - } - } - - // only three racks - StaticDNSResolver.addNodeToRack("98.98.98.0", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.1", "/rack2"); - StaticDNSResolver.addNodeToRack("98.98.98.2", "/rack3"); - StaticDNSResolver.addNodeToRack("98.98.98.3", "/rack4"); - StaticDNSResolver.addNodeToRack("98.98.98.4", "/rack1"); - StaticDNSResolver.addNodeToRack("98.98.98.5", "/rack2"); - StaticDNSResolver.addNodeToRack("98.98.98.6", "/rack3"); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - int ensembleSize = 5; - int writeQuorumSize = 5; - int ackQuorumSize = 2; - int minNumRacksPerWriteQuorumConfValue = 4; - - /* - * this closed ledger in each writeQuorumSize (5), there would be - * atleast minNumRacksPerWriteQuorumConfValue (4) racks. So it wont be - * counted as ledgers not adhering to placement policy. - */ - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(1L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses.subList(0, 5)) - .newEnsembleEntry(20L, bookieAddresses.subList(1, 6)) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(1L, initMeta).get(); - - /* - * for the second segment bookies are from /rack1, /rack2 and /rack3, - * which is < minNumRacksPerWriteQuorumConfValue (4). So it is not - * adhering to placement policy. - * - * also for the third segment are from /rack1, /rack2 and /rack3, which - * is < minNumRacksPerWriteQuorumConfValue (4). So it is not adhering to - * placement policy. - * - * Though there are multiple segments are not adhering to placement - * policy, it should be counted as single ledger. - */ - initMeta = LedgerMetadataBuilder.create() - .withId(2L) - .withEnsembleSize(ensembleSize) - .withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize) - .newEnsembleEntry(0L, bookieAddresses.subList(0, 5)) - .newEnsembleEntry(20L, - Arrays.asList(bookieAddresses.get(0), bookieAddresses.get(1), bookieAddresses.get(2), - bookieAddresses.get(4), bookieAddresses.get(5))) - .newEnsembleEntry(40L, - Arrays.asList(bookieAddresses.get(0), bookieAddresses.get(1), bookieAddresses.get(2), - bookieAddresses.get(4), bookieAddresses.get(6))) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(2L, initMeta).get(); - numOfLedgersNotAdheringToPlacementPolicy++; - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - setServerConfigPropertiesForRackPlacement(servConf); - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge ledgersNotAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY gauge value", - numOfLedgersNotAdheringToPlacementPolicy, ledgersNotAdheringToPlacementPolicyGuage.getSample()); - Gauge ledgersSoftlyAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY gauge value", - 0, ledgersSoftlyAdheringToPlacementPolicyGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - } - - @Test - public void testZoneawarePlacementPolicyCheck() throws Exception { - int numOfBookies = 6; - int numOfLedgersNotAdheringToPlacementPolicy = 0; - int numOfLedgersSoftlyAdheringToPlacementPolicy = 0; - List bookieAddresses = new ArrayList(); - try (RegistrationManager regManager = driver.createRegistrationManager()) { - /* - * 6 bookies - 3 zones and 2 uds - */ - for (int i = 0; i < numOfBookies; i++) { - BookieSocketAddress bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181); - bookieAddresses.add(bookieAddress.toBookieId()); - regManager.registerBookie(bookieAddress.toBookieId(), false, BookieServiceInfo.EMPTY); - String zone = "/zone" + (i % 3); - String upgradeDomain = "/ud" + (i % 2); - String networkLocation = zone + upgradeDomain; - StaticDNSResolver.addNodeToRack(bookieAddress.getHostName(), networkLocation); - } - } - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setDesiredNumZonesPerWriteQuorum(3); - servConf.setMinNumZonesPerWriteQuorum(2); - setServerConfigPropertiesForZonePlacement(servConf); - - /* - * this closed ledger adheres to ZoneAwarePlacementPolicy, since - * ensemble is spread across 3 zones and 2 UDs - */ - LedgerMetadata initMeta = LedgerMetadataBuilder.create() - .withId(1L) - .withEnsembleSize(6) - .withWriteQuorumSize(6) - .withAckQuorumSize(2) - .newEnsembleEntry(0L, bookieAddresses) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(1L, initMeta).get(); - - /* - * this is non-closed ledger, so though ensemble is not adhering to - * placement policy (since ensemble is not multiple of writeQuorum), - * this shouldn't be reported - */ - initMeta = LedgerMetadataBuilder.create() - .withId(2L) - .withEnsembleSize(6) - .withWriteQuorumSize(5) - .withAckQuorumSize(2) - .newEnsembleEntry(0L, bookieAddresses) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(2L, initMeta).get(); - - /* - * this is closed ledger, since ensemble is not multiple of writeQuorum, - * this ledger is not adhering to placement policy. - */ - initMeta = LedgerMetadataBuilder.create() - .withId(3L) - .withEnsembleSize(6) - .withWriteQuorumSize(5) - .withAckQuorumSize(2) - .newEnsembleEntry(0L, bookieAddresses) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(3L, initMeta).get(); - numOfLedgersNotAdheringToPlacementPolicy++; - - /* - * this closed ledger adheres softly to ZoneAwarePlacementPolicy, since - * ensemble/writeQuorum of size 4 has spread across just - * minNumZonesPerWriteQuorum (2). - */ - List newEnsemble = new ArrayList(); - newEnsemble.add(bookieAddresses.get(0)); - newEnsemble.add(bookieAddresses.get(1)); - newEnsemble.add(bookieAddresses.get(3)); - newEnsemble.add(bookieAddresses.get(4)); - initMeta = LedgerMetadataBuilder.create() - .withId(4L) - .withEnsembleSize(4) - .withWriteQuorumSize(4) - .withAckQuorumSize(2) - .newEnsembleEntry(0L, newEnsemble) - .withClosedState() - .withLastEntryId(100) - .withLength(10000) - .withDigestType(DigestType.DUMMY) - .withPassword(new byte[0]) - .build(); - lm.createLedgerMetadata(4L, initMeta).get(); - numOfLedgersSoftlyAdheringToPlacementPolicy++; - - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge ledgersNotAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY guage value", - numOfLedgersNotAdheringToPlacementPolicy, ledgersNotAdheringToPlacementPolicyGuage.getSample()); - Gauge ledgersSoftlyAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY guage value", - numOfLedgersSoftlyAdheringToPlacementPolicy, - ledgersSoftlyAdheringToPlacementPolicyGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - } - - private void setServerConfigPropertiesForRackPlacement(ServerConfiguration servConf) { - setServerConfigProperties(servConf, RackawareEnsemblePlacementPolicy.class.getName()); - } - - private void setServerConfigPropertiesForZonePlacement(ServerConfiguration servConf) { - setServerConfigProperties(servConf, ZoneawareEnsemblePlacementPolicy.class.getName()); - } - - private void setServerConfigProperties(ServerConfiguration servConf, String ensemblePlacementPolicyClass) { - servConf.setProperty(REPP_DNS_RESOLVER_CLASS, StaticDNSResolver.class.getName()); - servConf.setProperty(ClientConfiguration.ENSEMBLE_PLACEMENT_POLICY, ensemblePlacementPolicyClass); - servConf.setAuditorPeriodicCheckInterval(0); - servConf.setAuditorPeriodicBookieCheckInterval(0); - servConf.setAuditorPeriodicReplicasCheckInterval(0); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(1000); - } - - private TestStatsLogger startAuditorAndWaitForPlacementPolicyCheck(ServerConfiguration servConf, - MutableObject auditorRef) throws MetadataException, CompatibilityException, KeeperException, - InterruptedException, UnavailableException, UnknownHostException { - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - TestOpStatsLogger placementPolicyCheckStatsLogger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.PLACEMENT_POLICY_CHECK_TIME); - - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, - statsLogger, null); - auditorRef.setValue(auditor); - CountDownLatch latch = auditor.getLatch(); - assertEquals("PLACEMENT_POLICY_CHECK_TIME SuccessCount", 0, placementPolicyCheckStatsLogger.getSuccessCount()); - urm.setPlacementPolicyCheckCTime(-1); - auditor.start(); - /* - * since placementPolicyCheckCTime is set to -1, placementPolicyCheck should be - * scheduled to run with no initialdelay - */ - assertTrue("placementPolicyCheck should have executed", latch.await(20, TimeUnit.SECONDS)); - for (int i = 0; i < 20; i++) { - Thread.sleep(100); - if (placementPolicyCheckStatsLogger.getSuccessCount() >= 1) { - break; - } - } - assertEquals("PLACEMENT_POLICY_CHECK_TIME SuccessCount", 1, placementPolicyCheckStatsLogger.getSuccessCount()); - return statsLogger; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTaskTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTaskTest.java deleted file mode 100644 index f39a9dace7f..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTaskTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.junit.Assert.assertEquals; - -import java.util.LinkedList; -import java.util.List; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Unit test {@link AuditorReplicasCheckTask}. - */ -public class AuditorReplicasCheckTaskTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory - .getLogger(AuditorReplicasCheckTaskTest.class); - - private BookKeeperAdmin admin; - private LedgerManager ledgerManager; - private LedgerUnderreplicationManager ledgerUnderreplicationManager; - - public AuditorReplicasCheckTaskTest() { - super(3); - baseConf.setPageLimit(1); - baseConf.setAutoRecoveryDaemonEnabled(false); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - final BookKeeper bookKeeper = new BookKeeper(baseClientConf); - admin = new BookKeeperAdmin(bookKeeper, NullStatsLogger.INSTANCE, new ClientConfiguration(baseClientConf)); - LedgerManagerFactory ledgerManagerFactory = bookKeeper.getLedgerManagerFactory(); - ledgerManager = ledgerManagerFactory.newLedgerManager(); - ledgerUnderreplicationManager = ledgerManagerFactory.newLedgerUnderreplicationManager(); - } - - @Test - public void testReplicasCheck() throws BKException, InterruptedException { - - // 1. create ledgers - final int numLedgers = 10; - List ids = new LinkedList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, "passwd".getBytes()); - ids.add(lh.getId()); - for (int j = 0; j < 2; j++) { - lh.addEntry("testdata".getBytes()); - } - lh.close(); - } - - // 2. init auditorReplicasCheckTask - final TestStatsProvider statsProvider = new TestStatsProvider(); - final TestStatsProvider.TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - final AuditorStats auditorStats = new AuditorStats(statsLogger); - AuditorReplicasCheckTask auditorReplicasCheckTask = new AuditorReplicasCheckTask( - baseConf, auditorStats, admin, ledgerManager, - ledgerUnderreplicationManager, null, (flag, throwable) -> flag.set(false)); - - // 3. replicasCheck - auditorReplicasCheckTask.runTask(); - - // 4. verify - assertEquals("REPLICAS_CHECK_TIME", 1, ((TestStatsProvider.TestOpStatsLogger) - statsLogger.getOpStatsLogger(ReplicationStats.REPLICAS_CHECK_TIME)).getSuccessCount()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTest.java deleted file mode 100644 index c64a14eca28..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTest.java +++ /dev/null @@ -1,931 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.net.URI; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.BookieServiceInfo; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.exceptions.MetadataException; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.replication.AuditorPeriodicCheckTest.TestAuditor; -import org.apache.bookkeeper.replication.ReplicationException.CompatibilityException; -import org.apache.bookkeeper.replication.ReplicationException.UnavailableException; -import org.apache.bookkeeper.stats.Gauge; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.apache.bookkeeper.util.AvailabilityOfEntriesOfLedger; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.apache.commons.collections4.map.MultiKeyMap; -import org.apache.commons.lang3.mutable.MutableObject; -import org.apache.zookeeper.KeeperException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Tests the logic of Auditor's ReplicasCheck. - */ -public class AuditorReplicasCheckTest extends BookKeeperClusterTestCase { - private MetadataBookieDriver driver; - private RegistrationManager regManager; - - public AuditorReplicasCheckTest() { - super(1); - baseConf.setPageLimit(1); // to make it easy to push ledger out of cache - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - StaticDNSResolver.reset(); - driver = MetadataDrivers.getBookieDriver(URI.create(confByIndex(0).getMetadataServiceUri())); - driver.initialize(confByIndex(0), NullStatsLogger.INSTANCE); - regManager = driver.createRegistrationManager(); - } - - @After - @Override - public void tearDown() throws Exception { - if (null != regManager) { - regManager.close(); - } - if (null != driver) { - driver.close(); - } - super.tearDown(); - } - - private class TestBookKeeperAdmin extends BookKeeperAdmin { - - private final MultiKeyMap returnAvailabilityOfEntriesOfLedger; - private final MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger; - - public TestBookKeeperAdmin(BookKeeper bkc, StatsLogger statsLogger, - MultiKeyMap returnAvailabilityOfEntriesOfLedger, - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger) { - super(bkc, statsLogger, baseClientConf); - this.returnAvailabilityOfEntriesOfLedger = returnAvailabilityOfEntriesOfLedger; - this.errorReturnValueForGetAvailabilityOfEntriesOfLedger = - errorReturnValueForGetAvailabilityOfEntriesOfLedger; - } - - @Override - public CompletableFuture asyncGetListOfEntriesOfLedger( - BookieId address, long ledgerId) { - CompletableFuture futureResult = - new CompletableFuture(); - Integer errorReturnValue = errorReturnValueForGetAvailabilityOfEntriesOfLedger.get(address.toString(), - Long.toString(ledgerId)); - if (errorReturnValue != null) { - futureResult.completeExceptionally(BKException.create(errorReturnValue).fillInStackTrace()); - } else { - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = returnAvailabilityOfEntriesOfLedger - .get(address.toString(), Long.toString(ledgerId)); - futureResult.complete(availabilityOfEntriesOfLedger); - } - return futureResult; - } - } - - private TestStatsLogger startAuditorAndWaitForReplicasCheck(ServerConfiguration servConf, - MutableObject auditorRef, - MultiKeyMap expectedReturnAvailabilityOfEntriesOfLedger, - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger) - throws MetadataException, CompatibilityException, KeeperException, InterruptedException, - UnavailableException, UnknownHostException { - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - TestOpStatsLogger replicasCheckStatsLogger = (TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.REPLICAS_CHECK_TIME); - - final TestAuditor auditor = new TestAuditor(BookieImpl.getBookieId(servConf).toString(), servConf, bkc, true, - new TestBookKeeperAdmin(bkc, statsLogger, expectedReturnAvailabilityOfEntriesOfLedger, - errorReturnValueForGetAvailabilityOfEntriesOfLedger), - true, statsLogger, null); - auditorRef.setValue(auditor); - CountDownLatch latch = auditor.getLatch(); - assertEquals("REPLICAS_CHECK_TIME SuccessCount", 0, replicasCheckStatsLogger.getSuccessCount()); - urm.setReplicasCheckCTime(-1); - auditor.start(); - /* - * since replicasCheckCTime is set to -1, replicasCheck should be - * scheduled to run with no initialdelay - */ - assertTrue("replicasCheck should have executed", latch.await(20, TimeUnit.SECONDS)); - for (int i = 0; i < 200; i++) { - Thread.sleep(100); - if (replicasCheckStatsLogger.getSuccessCount() >= 1) { - break; - } - } - assertEquals("REPLICAS_CHECK_TIME SuccessCount", 1, replicasCheckStatsLogger.getSuccessCount()); - return statsLogger; - } - - private void setServerConfigProperties(ServerConfiguration servConf) { - servConf.setAuditorPeriodicCheckInterval(0); - servConf.setAuditorPeriodicBookieCheckInterval(0); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(0); - servConf.setAuditorPeriodicReplicasCheckInterval(1000); - } - - List addAndRegisterBookies(int numOfBookies) - throws BookieException { - BookieId bookieAddress; - List bookieAddresses = new ArrayList(); - for (int i = 0; i < numOfBookies; i++) { - bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181).toBookieId(); - bookieAddresses.add(bookieAddress); - regManager.registerBookie(bookieAddress, false, BookieServiceInfo.EMPTY); - } - return bookieAddresses; - } - - private void createClosedLedgerMetadata(LedgerManager lm, long ledgerId, int ensembleSize, int writeQuorumSize, - int ackQuorumSize, Map> segmentEnsembles, long lastEntryId, int length, - DigestType digestType, byte[] password) throws InterruptedException, ExecutionException { - LedgerMetadataBuilder ledgerMetadataBuilder = LedgerMetadataBuilder.create(); - ledgerMetadataBuilder.withId(ledgerId).withEnsembleSize(ensembleSize).withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize).withClosedState().withLastEntryId(lastEntryId).withLength(length) - .withDigestType(digestType).withPassword(password); - for (Map.Entry> mapEntry : segmentEnsembles.entrySet()) { - ledgerMetadataBuilder.newEnsembleEntry(mapEntry.getKey(), mapEntry.getValue()); - } - LedgerMetadata initMeta = ledgerMetadataBuilder.build(); - lm.createLedgerMetadata(ledgerId, initMeta).get(); - } - - private void createNonClosedLedgerMetadata(LedgerManager lm, long ledgerId, int ensembleSize, int writeQuorumSize, - int ackQuorumSize, Map> segmentEnsembles, DigestType digestType, - byte[] password) throws InterruptedException, ExecutionException { - LedgerMetadataBuilder ledgerMetadataBuilder = LedgerMetadataBuilder.create(); - ledgerMetadataBuilder.withId(ledgerId).withEnsembleSize(ensembleSize).withWriteQuorumSize(writeQuorumSize) - .withAckQuorumSize(ackQuorumSize).withDigestType(digestType).withPassword(password); - for (Map.Entry> mapEntry : segmentEnsembles.entrySet()) { - ledgerMetadataBuilder.newEnsembleEntry(mapEntry.getKey(), mapEntry.getValue()); - } - LedgerMetadata initMeta = ledgerMetadataBuilder.build(); - lm.createLedgerMetadata(ledgerId, initMeta).get(); - } - - private void runTestScenario(MultiKeyMap returnAvailabilityOfEntriesOfLedger, - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger, - int expectedNumLedgersFoundHavingNoReplicaOfAnEntry, - int expectedNumLedgersHavingLessThanAQReplicasOfAnEntry, - int expectedNumLedgersHavingLessThanWQReplicasOfAnEntry) throws Exception { - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - setServerConfigProperties(servConf); - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForReplicasCheck(servConf, auditorRef, - returnAvailabilityOfEntriesOfLedger, errorReturnValueForGetAvailabilityOfEntriesOfLedger); - checkReplicasCheckStats(statsLogger, expectedNumLedgersFoundHavingNoReplicaOfAnEntry, - expectedNumLedgersHavingLessThanAQReplicasOfAnEntry, - expectedNumLedgersHavingLessThanWQReplicasOfAnEntry); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - } - - private void checkReplicasCheckStats(TestStatsLogger statsLogger, - int expectedNumLedgersFoundHavingNoReplicaOfAnEntry, - int expectedNumLedgersHavingLessThanAQReplicasOfAnEntry, - int expectedNumLedgersHavingLessThanWQReplicasOfAnEntry) { - Gauge numLedgersFoundHavingNoReplicaOfAnEntryGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_HAVING_NO_REPLICA_OF_AN_ENTRY); - Gauge numLedgersHavingLessThanAQReplicasOfAnEntryGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_HAVING_LESS_THAN_AQ_REPLICAS_OF_AN_ENTRY); - Gauge numLedgersHavingLessThanWQReplicasOfAnEntryGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_HAVING_LESS_THAN_WQ_REPLICAS_OF_AN_ENTRY); - - assertEquals("NUM_LEDGERS_HAVING_NO_REPLICA_OF_AN_ENTRY guage value", - expectedNumLedgersFoundHavingNoReplicaOfAnEntry, - numLedgersFoundHavingNoReplicaOfAnEntryGuage.getSample()); - assertEquals("NUM_LEDGERS_HAVING_LESS_THAN_AQ_REPLICAS_OF_AN_ENTRY guage value", - expectedNumLedgersHavingLessThanAQReplicasOfAnEntry, - numLedgersHavingLessThanAQReplicasOfAnEntryGuage.getSample()); - assertEquals("NUM_LEDGERS_HAVING_LESS_THAN_WQ_REPLICAS_OF_AN_ENTRY guage value", - expectedNumLedgersHavingLessThanWQReplicasOfAnEntry, - numLedgersHavingLessThanWQReplicasOfAnEntryGuage.getSample()); - } - - /* - * For all the ledgers and for all the bookies, - * asyncGetListOfEntriesOfLedger would return - * BookieHandleNotAvailableException, so these ledgers wouldn't be counted - * against expectedNumLedgersFoundHavingNoReplicaOfAnEntry / - * LessThanAQReplicasOfAnEntry / LessThanWQReplicasOfAnEntry. - */ - @Test - public void testReplicasCheckForBookieHandleNotAvailable() throws Exception { - int numOfBookies = 5; - MultiKeyMap returnAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - List bookieAddresses = addAndRegisterBookies(numOfBookies); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - int ensembleSize = 5; - int writeQuorumSize = 4; - int ackQuorumSize = 2; - long lastEntryId = 100; - int length = 10000; - DigestType digestType = DigestType.DUMMY; - byte[] password = new byte[0]; - Collections.shuffle(bookieAddresses); - - /* - * closed ledger - * - * for this ledger, for all the bookies we are setting - * errorReturnValueForGetAvailabilityOfEntriesOfLedger to - * BookieHandleNotAvailableException so asyncGetListOfEntriesOfLedger will - * return BookieHandleNotAvailableException. - */ - Map> segmentEnsembles = new LinkedHashMap>(); - segmentEnsembles.put(0L, bookieAddresses); - long ledgerId = 1L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), - Long.toString(ledgerId), BKException.Code.BookieHandleNotAvailableException); - } - - ensembleSize = 4; - /* - * closed ledger with multiple segments - * - * for this ledger, for all the bookies we are setting - * errorReturnValueForGetAvailabilityOfEntriesOfLedger to - * BookieHandleNotAvailableException so asyncGetListOfEntriesOfLedger will - * return BookieHandleNotAvailableException. - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(20L, bookieAddresses.subList(1, 5)); - segmentEnsembles.put(60L, bookieAddresses.subList(0, 4)); - ledgerId = 2L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), - Long.toString(ledgerId), BKException.Code.BookieHandleNotAvailableException); - } - - /* - * non-closed ledger - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - ledgerId = 3L; - createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), - Long.toString(ledgerId), BKException.Code.BookieHandleNotAvailableException); - } - - /* - * non-closed ledger with multiple segments - * - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(20L, bookieAddresses.subList(1, 5)); - segmentEnsembles.put(60L, bookieAddresses.subList(0, 4)); - ledgerId = 4L; - createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), - Long.toString(ledgerId), BKException.Code.BookieHandleNotAvailableException); - } - - runTestScenario(returnAvailabilityOfEntriesOfLedger, errorReturnValueForGetAvailabilityOfEntriesOfLedger, 0, 0, - 0); - } - - /* - * In this testscenario all the ledgers have a missing entry. So all closed - * ledgers should be counted towards - * numLedgersFoundHavingNoReplicaOfAnEntry. - */ - @Test - public void testReplicasCheckForLedgersFoundHavingNoReplica() throws Exception { - int numOfBookies = 5; - MultiKeyMap returnAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - List bookieAddresses = addAndRegisterBookies(numOfBookies); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - int ensembleSize = 5; - int writeQuorumSize = 4; - int ackQuorumSize = 2; - long lastEntryId = 100; - int length = 10000; - DigestType digestType = DigestType.DUMMY; - byte[] password = new byte[0]; - Collections.shuffle(bookieAddresses); - - int numLedgersFoundHavingNoReplicaOfAnEntry = 0; - - /* - * closed ledger - * - * for this ledger we are setting returnAvailabilityOfEntriesOfLedger to - * Empty one for all of the bookies, so this ledger would be counted in - * ledgersFoundHavingNoReplicaOfAnEntry . - */ - Map> segmentEnsembles = new LinkedHashMap>(); - segmentEnsembles.put(0L, bookieAddresses); - long ledgerId = 1L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - returnAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), Long.toString(ledgerId), - AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER); - } - numLedgersFoundHavingNoReplicaOfAnEntry++; - - ensembleSize = 4; - /* - * closed ledger with multiple segments - * - * for this ledger we are setting - * errorReturnValueForGetAvailabilityOfEntriesOfLedger to - * NoSuchLedgerExistsException. This is equivalent to - * EMPTY_AVAILABILITYOFENTRIESOFLEDGER. So this ledger would be counted - * in ledgersFoundHavingNoReplicaOfAnEntry - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(20L, bookieAddresses.subList(1, 5)); - segmentEnsembles.put(60L, bookieAddresses.subList(0, 4)); - ledgerId = 2L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), - Long.toString(ledgerId), BKException.Code.NoSuchLedgerExistsException); - } - numLedgersFoundHavingNoReplicaOfAnEntry++; - - /* - * non-closed ledger - * - * since this is non-closed ledger, it should not be counted in - * ledgersFoundHavingNoReplicaOfAnEntry - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - ledgerId = 3L; - createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - returnAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), Long.toString(ledgerId), - AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER); - } - - ensembleSize = 3; - writeQuorumSize = 3; - ackQuorumSize = 2; - lastEntryId = 1; - length = 1000; - /* - * closed ledger - * - * for this ledger we are setting returnAvailabilityOfEntriesOfLedger to - * just {0l} for all of the bookies and entry 1l is missing for all of - * the bookies, so this ledger would be counted in - * ledgersFoundHavingNoReplicaOfAnEntry - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 3)); - ledgerId = 4L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - for (BookieId bookieSocketAddress : bookieAddresses) { - returnAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0L })); - } - numLedgersFoundHavingNoReplicaOfAnEntry++; - - /* - * For this closed ledger, entry 1 is missing. So it should be counted - * towards numLedgersFoundHavingNoReplicaOfAnEntry. - */ - ensembleSize = 4; - writeQuorumSize = 3; - ackQuorumSize = 2; - lastEntryId = 3; - length = 10000; - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - ledgerId = 5L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 2, 3 })); - numLedgersFoundHavingNoReplicaOfAnEntry++; - - runTestScenario(returnAvailabilityOfEntriesOfLedger, errorReturnValueForGetAvailabilityOfEntriesOfLedger, - numLedgersFoundHavingNoReplicaOfAnEntry, 0, 0); - } - - /* - * In this testscenario all the ledgers have an entry with less than AQ - * number of copies. So all closed ledgers should be counted towards - * numLedgersFoundHavingLessThanAQReplicasOfAnEntry. - */ - @Test - public void testReplicasCheckForLedgersFoundHavingLessThanAQReplicasOfAnEntry() throws Exception { - int numOfBookies = 5; - MultiKeyMap returnAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - List bookieAddresses = addAndRegisterBookies(numOfBookies); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - DigestType digestType = DigestType.DUMMY; - byte[] password = new byte[0]; - Collections.shuffle(bookieAddresses); - - int numLedgersFoundHavingLessThanAQReplicasOfAnEntry = 0; - - /* - * closed ledger - * - * for this ledger there is only one copy of entry 2, so this ledger - * would be counted towards - * ledgersFoundHavingLessThanAQReplicasOfAnEntry. - */ - Map> segmentEnsembles = new LinkedHashMap>(); - int ensembleSize = 4; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - long lastEntryId = 3; - int length = 10000; - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - long ledgerId = 1L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1, 2, 3 })); - numLedgersFoundHavingLessThanAQReplicasOfAnEntry++; - - /* - * closed ledger with multiple segments. - * - * for this ledger there is only one copy of entry 2, so this ledger - * would be counted towards - * ledgersFoundHavingLessThanAQReplicasOfAnEntry. - * - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(2L, bookieAddresses.subList(1, 5)); - ledgerId = 2L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] {})); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 3 })); - numLedgersFoundHavingLessThanAQReplicasOfAnEntry++; - - /* - * closed ledger with multiple segments - * - * for this ledger entry 2 is overrreplicated, but it has only one copy - * in the set of bookies it is supposed to be. So it should be counted - * towards ledgersFoundHavingLessThanAQReplicasOfAnEntry. - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(2L, bookieAddresses.subList(1, 5)); - ledgerId = 3L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 3 })); - numLedgersFoundHavingLessThanAQReplicasOfAnEntry++; - - /* - * non-closed ledger - * - * since this is non-closed ledger, it should not be counted towards - * ledgersFoundHavingLessThanAQReplicasOfAnEntry - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(2L, bookieAddresses.subList(1, 5)); - ledgerId = 4L; - createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] {})); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 3 })); - - /* - * this is closed ledger. - * - * For third bookie, asyncGetListOfEntriesOfLedger will fail with - * BookieHandleNotAvailableException, so this should not be counted - * against missing copies of an entry. Other than that, for both entries - * 0 and 1, two copies are missing. Hence this should be counted towards - * numLedgersFoundHavingLessThanAQReplicasOfAnEntry. - */ - ensembleSize = 3; - writeQuorumSize = 3; - ackQuorumSize = 2; - lastEntryId = 1; - length = 1000; - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 3)); - ledgerId = 5L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER); - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), - Long.toString(ledgerId), BKException.Code.BookieHandleNotAvailableException); - numLedgersFoundHavingLessThanAQReplicasOfAnEntry++; - - runTestScenario(returnAvailabilityOfEntriesOfLedger, errorReturnValueForGetAvailabilityOfEntriesOfLedger, 0, - numLedgersFoundHavingLessThanAQReplicasOfAnEntry, 0); - } - - /* - * In this testscenario all the ledgers have an entry with less than WQ - * number of copies but greater than AQ. So all closed ledgers should be - * counted towards numLedgersFoundHavingLessThanWQReplicasOfAnEntry. - */ - @Test - public void testReplicasCheckForLedgersFoundHavingLessThanWQReplicasOfAnEntry() throws Exception { - int numOfBookies = 5; - MultiKeyMap returnAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - List bookieAddresses = addAndRegisterBookies(numOfBookies); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - DigestType digestType = DigestType.DUMMY; - byte[] password = new byte[0]; - Collections.shuffle(bookieAddresses); - - int numLedgersFoundHavingLessThanWQReplicasOfAnEntry = 0; - - /* - * closed ledger - * - * for this ledger a copy of entry 3, so this ledger would be counted - * towards ledgersFoundHavingLessThanWQReplicasOfAnEntry. - */ - Map> segmentEnsembles = new LinkedHashMap>(); - int ensembleSize = 4; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - long lastEntryId = 3; - int length = 10000; - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - long ledgerId = 1L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1, 2, 3 })); - numLedgersFoundHavingLessThanWQReplicasOfAnEntry++; - - /* - * closed ledger with multiple segments - * - * for this ledger a copy of entry 0 and entry 2 are missing, so this - * ledger would be counted towards - * ledgersFoundHavingLessThanWQReplicasOfAnEntry. - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(2L, bookieAddresses.subList(1, 5)); - ledgerId = 2L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] {})); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 2, 3 })); - numLedgersFoundHavingLessThanWQReplicasOfAnEntry++; - - /* - * non-closed ledger with multiple segments - * - * since this is non-closed ledger, it should not be counted towards - * ledgersFoundHavingLessThanWQReplicasOfAnEntry - */ - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(2L, bookieAddresses.subList(1, 5)); - ledgerId = 3L; - createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - digestType, password); - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), - Long.toString(ledgerId), BKException.Code.NoSuchLedgerExistsException); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 2, 3 })); - - /* - * closed ledger. - * - * for this ledger entry 0 is overrreplicated, but a copy is missing in - * the set of bookies it is supposed to be. So it should be counted - * towards ledgersFoundHavingLessThanWQReplicasOfAnEntry. - */ - ensembleSize = 4; - writeQuorumSize = 3; - ackQuorumSize = 2; - lastEntryId = 1; - length = 1000; - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - ledgerId = 4L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1, 3 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0 })); - numLedgersFoundHavingLessThanWQReplicasOfAnEntry++; - - /* - * this is closed ledger. - * - * For third bookie, asyncGetListOfEntriesOfLedger will fail with - * BookieHandleNotAvailableException, so this should not be counted - * against missing copies of an entry. Other than that, for both entries - * 0 and 1, a copy is missing. Hence this should be counted towards - * numLedgersFoundHavingLessThanWQReplicasOfAnEntry. - */ - ensembleSize = 3; - writeQuorumSize = 3; - ackQuorumSize = 2; - lastEntryId = 1; - length = 1000; - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 3)); - ledgerId = 5L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 })); - errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), - Long.toString(ledgerId), BKException.Code.BookieHandleNotAvailableException); - numLedgersFoundHavingLessThanWQReplicasOfAnEntry++; - - runTestScenario(returnAvailabilityOfEntriesOfLedger, errorReturnValueForGetAvailabilityOfEntriesOfLedger, 0, 0, - numLedgersFoundHavingLessThanWQReplicasOfAnEntry); - } - - /* - * In this testscenario all the ledgers have empty segments. - */ - @Test - public void testReplicasCheckForLedgersWithEmptySegments() throws Exception { - int numOfBookies = 5; - MultiKeyMap returnAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - MultiKeyMap errorReturnValueForGetAvailabilityOfEntriesOfLedger = - new MultiKeyMap(); - List bookieAddresses = addAndRegisterBookies(numOfBookies); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerManager lm = mFactory.newLedgerManager(); - DigestType digestType = DigestType.DUMMY; - byte[] password = new byte[0]; - Collections.shuffle(bookieAddresses); - - int numLedgersFoundHavingNoReplicaOfAnEntry = 0; - int numLedgersFoundHavingLessThanAQReplicasOfAnEntry = 0; - int numLedgersFoundHavingLessThanWQReplicasOfAnEntry = 0; - - /* - * closed ledger. - * - * This closed Ledger has no entry. So it should not be counted towards - * numLedgersFoundHavingNoReplicaOfAnEntry/LessThanAQReplicasOfAnEntry - * /WQReplicasOfAnEntry. - */ - Map> segmentEnsembles = new LinkedHashMap>(); - int ensembleSize = 4; - int writeQuorumSize = 3; - int ackQuorumSize = 2; - long lastEntryId = -1L; - int length = 0; - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - long ledgerId = 1L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - - /* - * closed ledger with multiple segments. - * - * This ledger has empty last segment, but all the entries have - * writeQuorumSize number of copies, So it should not be counted towards - * numLedgersFoundHavingNoReplicaOfAnEntry/LessThanAQReplicasOfAnEntry/ - * WQReplicasOfAnEntry. - */ - lastEntryId = 2; - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put((lastEntryId + 1), bookieAddresses.subList(1, 5)); - ledgerId = 2L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1, 2 })); - - /* - * Closed ledger with multiple segments. - * - * Segment0, Segment1, Segment3, Segment5 and Segment6 are empty. - * Entries from entryid 3 are missing. So it should be counted towards - * numLedgersFoundHavingNoReplicaOfAnEntry. - */ - lastEntryId = 5; - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(1, 5)); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(4L, bookieAddresses.subList(1, 5)); - segmentEnsembles.put(4L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put((lastEntryId + 1), bookieAddresses.subList(1, 5)); - segmentEnsembles.put((lastEntryId + 1), bookieAddresses.subList(0, 4)); - ledgerId = 3L; - createClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - lastEntryId, length, digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1, 2 })); - numLedgersFoundHavingNoReplicaOfAnEntry++; - - /* - * non-closed ledger with multiple segments - * - * since this is non-closed ledger, it should not be counted towards - * ledgersFoundHavingLessThanWQReplicasOfAnEntry - */ - lastEntryId = 2; - segmentEnsembles.clear(); - segmentEnsembles.put(0L, bookieAddresses.subList(0, 4)); - segmentEnsembles.put(0L, bookieAddresses.subList(1, 5)); - segmentEnsembles.put((lastEntryId + 1), bookieAddresses.subList(1, 5)); - ledgerId = 4L; - createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, writeQuorumSize, ackQuorumSize, segmentEnsembles, - digestType, password); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2 })); - returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), Long.toString(ledgerId), - new AvailabilityOfEntriesOfLedger(new long[] { 1, 2 })); - - runTestScenario(returnAvailabilityOfEntriesOfLedger, errorReturnValueForGetAvailabilityOfEntriesOfLedger, - numLedgersFoundHavingNoReplicaOfAnEntry, numLedgersFoundHavingLessThanAQReplicasOfAnEntry, - numLedgersFoundHavingLessThanWQReplicasOfAnEntry); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorRollingRestartTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorRollingRestartTest.java deleted file mode 100644 index 6f734a38429..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorRollingRestartTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; -import static org.junit.Assert.assertEquals; - -import com.google.common.util.concurrent.UncheckedExecutionException; -import lombok.Cleanup; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerAuditorManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestCallbacks; -import org.junit.Test; - -/** - * Test auditor behaviours during a rolling restart. - */ -public class AuditorRollingRestartTest extends BookKeeperClusterTestCase { - - public AuditorRollingRestartTest() { - super(3, 600); - // run the daemon within the bookie - setAutoRecoveryEnabled(true); - } - - /** - * Test no auditing during restart if disabled. - */ - @Test - public void testAuditingDuringRollingRestart() throws Exception { - runFunctionWithLedgerManagerFactory( - confByIndex(0), - mFactory -> { - try { - testAuditingDuringRollingRestart(mFactory); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - return null; - } - ); - } - - private void testAuditingDuringRollingRestart(LedgerManagerFactory mFactory) throws Exception { - final LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - - LedgerHandle lh = bkc.createLedger(3, 3, DigestType.CRC32, "passwd".getBytes()); - for (int i = 0; i < 10; i++) { - lh.asyncAddEntry("foobar".getBytes(), new TestCallbacks.AddCallbackFuture(i), null); - } - lh.addEntry("foobar".getBytes()); - lh.close(); - - assertEquals("shouldn't be anything under replicated", - underReplicationManager.pollLedgerToRereplicate(), -1); - underReplicationManager.disableLedgerReplication(); - - @Cleanup - LedgerAuditorManager lam = mFactory.newLedgerAuditorManager(); - BookieId auditor = lam.getCurrentAuditor(); - ServerConfiguration conf = killBookie(auditor); - Thread.sleep(2000); - startBookie(conf); - Thread.sleep(2000); // give it time to run - assertEquals("shouldn't be anything under replicated", -1, - underReplicationManager.pollLedgerToRereplicate()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuthAutoRecoveryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuthAutoRecoveryTest.java deleted file mode 100644 index 33557b99d21..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuthAutoRecoveryTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.apache.bookkeeper.auth.AuthCallbacks; -import org.apache.bookkeeper.auth.AuthToken; -import org.apache.bookkeeper.auth.ClientAuthProvider; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.ClientConnectionPeer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This test verifies the auditor bookie scenarios from the auth point-of-view. - */ -public class AuthAutoRecoveryTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory - .getLogger(AuthAutoRecoveryTest.class); - - public static final String TEST_AUTH_PROVIDER_PLUGIN_NAME = "TestAuthProviderPlugin"; - - private static String clientSideRole; - - private static class AuditorClientAuthInterceptorFactory - implements ClientAuthProvider.Factory { - - @Override - public String getPluginName() { - return TEST_AUTH_PROVIDER_PLUGIN_NAME; - } - - @Override - public void init(ClientConfiguration conf) { - clientSideRole = conf.getClientRole(); - } - - @Override - public ClientAuthProvider newProvider(ClientConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new ClientAuthProvider() { - public void init(AuthCallbacks.GenericCallback cb) { - completeCb.operationComplete(BKException.Code.OK, null); - } - - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - } - }; - } - } - - protected ServerConfiguration newServerConfiguration() throws Exception { - ServerConfiguration conf = super.newServerConfiguration(); - conf.setClientAuthProviderFactoryClass(AuditorClientAuthInterceptorFactory.class.getName()); - return conf; - } - - public AuthAutoRecoveryTest() { - super(6); - } - - /* - * test the client role of the auditor - */ - @Test - public void testAuthClientRole() throws Exception { - ServerConfiguration config = confByIndex(0); - assertEquals(AuditorClientAuthInterceptorFactory.class.getName(), config.getClientAuthProviderFactoryClass()); - AutoRecoveryMain main = new AutoRecoveryMain(config); - try { - main.start(); - Thread.sleep(500); - assertTrue("AuditorElector should be running", - main.auditorElector.isRunning()); - assertTrue("Replication worker should be running", - main.replicationWorker.isRunning()); - } finally { - main.shutdown(); - } - assertEquals(ClientConfiguration.CLIENT_ROLE_SYSTEM, clientSideRole); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AutoRecoveryMainTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AutoRecoveryMainTest.java deleted file mode 100644 index a0e795034e7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AutoRecoveryMainTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.meta.zk.ZKMetadataClientDriver; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.TestUtils; -import org.apache.zookeeper.ZooKeeper; -import org.awaitility.Awaitility; -import org.junit.Test; - -/** - * Test the AuditorPeer. - */ -public class AutoRecoveryMainTest extends BookKeeperClusterTestCase { - - public AutoRecoveryMainTest() { - super(3); - } - - /** - * Test the startup of the auditorElector and RW. - */ - @Test - public void testStartup() throws Exception { - AutoRecoveryMain main = new AutoRecoveryMain(confByIndex(0)); - try { - main.start(); - Thread.sleep(500); - assertTrue("AuditorElector should be running", - main.auditorElector.isRunning()); - assertTrue("Replication worker should be running", - main.replicationWorker.isRunning()); - } finally { - main.shutdown(); - } - } - - /* - * Test the shutdown of all daemons - */ - @Test - public void testShutdown() throws Exception { - AutoRecoveryMain main = new AutoRecoveryMain(confByIndex(0)); - main.start(); - Thread.sleep(500); - assertTrue("AuditorElector should be running", - main.auditorElector.isRunning()); - assertTrue("Replication worker should be running", - main.replicationWorker.isRunning()); - - main.shutdown(); - assertFalse("AuditorElector should not be running", - main.auditorElector.isRunning()); - assertFalse("Replication worker should not be running", - main.replicationWorker.isRunning()); - } - - /** - * Test that, if an autorecovery looses its ZK connection/session it will - * shutdown. - */ - @Test - public void testAutoRecoverySessionLoss() throws Exception { - /* - * initialize three AutoRecovery instances. - */ - AutoRecoveryMain main1 = new AutoRecoveryMain(confByIndex(0)); - AutoRecoveryMain main2 = new AutoRecoveryMain(confByIndex(1)); - AutoRecoveryMain main3 = new AutoRecoveryMain(confByIndex(2)); - - /* - * start main1, make sure all the components are started and main1 is - * the current Auditor - */ - ZKMetadataClientDriver zkMetadataClientDriver1 = startAutoRecoveryMain(main1); - ZooKeeper zk1 = zkMetadataClientDriver1.getZk(); - - // Wait until auditor gets elected - for (int i = 0; i < 10; i++) { - try { - if (main1.auditorElector.getCurrentAuditor() != null) { - break; - } else { - Thread.sleep(1000); - } - } catch (IOException e) { - Thread.sleep(1000); - } - } - BookieId currentAuditor = main1.auditorElector.getCurrentAuditor(); - assertNotNull(currentAuditor); - Auditor auditor1 = main1.auditorElector.getAuditor(); - assertEquals("Current Auditor should be AR1", currentAuditor, BookieImpl.getBookieId(confByIndex(0))); - Awaitility.waitAtMost(30, TimeUnit.SECONDS).untilAsserted(() -> { - assertNotNull(auditor1); - assertTrue("Auditor of AR1 should be running", auditor1.isRunning()); - }); - - - /* - * start main2 and main3 - */ - ZKMetadataClientDriver zkMetadataClientDriver2 = startAutoRecoveryMain(main2); - ZooKeeper zk2 = zkMetadataClientDriver2.getZk(); - ZKMetadataClientDriver zkMetadataClientDriver3 = startAutoRecoveryMain(main3); - ZooKeeper zk3 = zkMetadataClientDriver3.getZk(); - - /* - * make sure AR1 is still the current Auditor and AR2's and AR3's - * auditors are not running. - */ - assertEquals("Current Auditor should still be AR1", currentAuditor, BookieImpl.getBookieId(confByIndex(0))); - Awaitility.await().untilAsserted(() -> { - assertTrue("AR2's Auditor should not be running", (main2.auditorElector.getAuditor() == null - || !main2.auditorElector.getAuditor().isRunning())); - assertTrue("AR3's Auditor should not be running", (main3.auditorElector.getAuditor() == null - || !main3.auditorElector.getAuditor().isRunning())); - }); - - - /* - * expire zk2 and zk1 sessions. - */ - zkUtil.expireSession(zk2); - zkUtil.expireSession(zk1); - - /* - * wait for some time for all the components of AR1 and AR2 are - * shutdown. - */ - for (int i = 0; i < 10; i++) { - if (!main1.auditorElector.isRunning() && !main1.replicationWorker.isRunning() - && !main1.isAutoRecoveryRunning() && !main2.auditorElector.isRunning() - && !main2.replicationWorker.isRunning() && !main2.isAutoRecoveryRunning()) { - break; - } - Thread.sleep(1000); - } - - /* - * the AR3 should be current auditor. - */ - currentAuditor = main3.auditorElector.getCurrentAuditor(); - assertEquals("Current Auditor should be AR3", currentAuditor, BookieImpl.getBookieId(confByIndex(2))); - Awaitility.await().untilAsserted(() -> { - assertNotNull(main3.auditorElector.getAuditor()); - assertTrue("Auditor of AR3 should be running", main3.auditorElector.getAuditor().isRunning()); - }); - - Awaitility.await().untilAsserted(() -> { - /* - * since AR3 is current auditor, AR1's auditor should not be running - * anymore. - */ - assertFalse("AR1's auditor should not be running", auditor1.isRunning()); - - /* - * components of AR2 and AR3 should not be running since zk1 and zk2 - * sessions are expired. - */ - assertFalse("Elector1 should have shutdown", main1.auditorElector.isRunning()); - assertFalse("RW1 should have shutdown", main1.replicationWorker.isRunning()); - assertFalse("AR1 should have shutdown", main1.isAutoRecoveryRunning()); - assertFalse("Elector2 should have shutdown", main2.auditorElector.isRunning()); - assertFalse("RW2 should have shutdown", main2.replicationWorker.isRunning()); - assertFalse("AR2 should have shutdown", main2.isAutoRecoveryRunning()); - }); - - } - - /* - * start autoRecoveryMain and make sure all its components are running and - * myVote node is existing - */ - ZKMetadataClientDriver startAutoRecoveryMain(AutoRecoveryMain autoRecoveryMain) throws Exception { - autoRecoveryMain.start(); - ZKMetadataClientDriver metadataClientDriver = (ZKMetadataClientDriver) autoRecoveryMain.bkc - .getMetadataClientDriver(); - TestUtils.assertEventuallyTrue("autoRecoveryMain components should be running", - () -> autoRecoveryMain.auditorElector.isRunning() - && autoRecoveryMain.replicationWorker.isRunning() && autoRecoveryMain.isAutoRecoveryRunning()); - return metadataClientDriver; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java deleted file mode 100644 index ccb262ed268..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.SortedMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.MetadataClientDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.replication.ReplicationException.CompatibilityException; -import org.apache.bookkeeper.replication.ReplicationException.UnavailableException; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.data.Stat; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Integration tests verifies the complete functionality of the - * Auditor-rereplication process: Auditor will publish the bookie failures, - * consequently ReplicationWorker will get the notifications and act on it. - */ -public class BookieAutoRecoveryTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory - .getLogger(BookieAutoRecoveryTest.class); - private static final byte[] PASSWD = "admin".getBytes(); - private static final byte[] data = "TESTDATA".getBytes(); - private static final String openLedgerRereplicationGracePeriod = "3000"; // milliseconds - - private DigestType digestType; - private MetadataClientDriver metadataClientDriver; - private LedgerManagerFactory mFactory; - private LedgerUnderreplicationManager underReplicationManager; - private LedgerManager ledgerManager; - private OrderedScheduler scheduler; - - private final String underreplicatedPath = "/ledgers/underreplication/ledgers"; - - public BookieAutoRecoveryTest() throws IOException, KeeperException, - InterruptedException, UnavailableException, CompatibilityException { - super(3); - - baseConf.setLedgerManagerFactoryClassName( - "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"); - baseConf.setOpenLedgerRereplicationGracePeriod(openLedgerRereplicationGracePeriod); - baseConf.setRwRereplicateBackoffMs(500); - baseClientConf.setLedgerManagerFactoryClassName( - "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"); - this.digestType = DigestType.MAC; - setAutoRecoveryEnabled(true); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - baseClientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduler") - .numThreads(1) - .build(); - - metadataClientDriver = MetadataDrivers.getClientDriver( - URI.create(baseClientConf.getMetadataServiceUri())); - metadataClientDriver.initialize( - baseClientConf, - scheduler, - NullStatsLogger.INSTANCE, - Optional.empty()); - - // initialize urReplicationManager - mFactory = metadataClientDriver.getLedgerManagerFactory(); - underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - ledgerManager = mFactory.newLedgerManager(); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - - if (null != underReplicationManager) { - underReplicationManager.close(); - underReplicationManager = null; - } - if (null != ledgerManager) { - ledgerManager.close(); - ledgerManager = null; - } - if (null != metadataClientDriver) { - metadataClientDriver.close(); - metadataClientDriver = null; - } - if (null != scheduler) { - scheduler.shutdown(); - } - } - - /** - * Test verifies publish urLedger by Auditor and replication worker is - * picking up the entries and finishing the rereplication of open ledger. - */ - @Test - public void testOpenLedgers() throws Exception { - List listOfLedgerHandle = createLedgersAndAddEntries(1, 5); - LedgerHandle lh = listOfLedgerHandle.get(0); - int ledgerReplicaIndex = 0; - BookieId replicaToKillAddr = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - final String urLedgerZNode = getUrLedgerZNode(lh); - ledgerReplicaIndex = getReplicaIndexInLedger(lh, replicaToKillAddr); - - CountDownLatch latch = new CountDownLatch(1); - assertNull("UrLedger already exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - - LOG.info("Killing Bookie :" + replicaToKillAddr); - killBookie(replicaToKillAddr); - - // waiting to publish urLedger znode by Auditor - latch.await(); - latch = new CountDownLatch(1); - LOG.info("Watching on urLedgerPath:" + urLedgerZNode - + " to know the status of rereplication process"); - assertNotNull("UrLedger doesn't exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - - // starting the replication service, so that he will be able to act as - // target bookie - startNewBookie(); - int newBookieIndex = lastBookieIndex(); - BookieServer newBookieServer = serverByIndex(newBookieIndex); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting to finish the replication of failed bookie : " - + replicaToKillAddr); - } - latch.await(); - - // grace period to update the urledger metadata in zookeeper - LOG.info("Waiting to update the urledger metadata in zookeeper"); - - verifyLedgerEnsembleMetadataAfterReplication(newBookieServer, - listOfLedgerHandle.get(0), ledgerReplicaIndex); - } - - /** - * Test verifies publish urLedger by Auditor and replication worker is - * picking up the entries and finishing the rereplication of closed ledgers. - */ - @Test - public void testClosedLedgers() throws Exception { - List listOfReplicaIndex = new ArrayList(); - List listOfLedgerHandle = createLedgersAndAddEntries(1, 5); - closeLedgers(listOfLedgerHandle); - LedgerHandle lhandle = listOfLedgerHandle.get(0); - int ledgerReplicaIndex = 0; - BookieId replicaToKillAddr = lhandle.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - CountDownLatch latch = new CountDownLatch(listOfLedgerHandle.size()); - for (LedgerHandle lh : listOfLedgerHandle) { - ledgerReplicaIndex = getReplicaIndexInLedger(lh, replicaToKillAddr); - listOfReplicaIndex.add(ledgerReplicaIndex); - assertNull("UrLedger already exists!", - watchUrLedgerNode(getUrLedgerZNode(lh), latch)); - } - - LOG.info("Killing Bookie :" + replicaToKillAddr); - killBookie(replicaToKillAddr); - - // waiting to publish urLedger znode by Auditor - latch.await(); - - // Again watching the urLedger znode to know the replication status - latch = new CountDownLatch(listOfLedgerHandle.size()); - for (LedgerHandle lh : listOfLedgerHandle) { - String urLedgerZNode = getUrLedgerZNode(lh); - LOG.info("Watching on urLedgerPath:" + urLedgerZNode - + " to know the status of rereplication process"); - assertNotNull("UrLedger doesn't exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - } - - // starting the replication service, so that he will be able to act as - // target bookie - startNewBookie(); - int newBookieIndex = lastBookieIndex(); - BookieServer newBookieServer = serverByIndex(newBookieIndex); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting to finish the replication of failed bookie : " - + replicaToKillAddr); - } - - // waiting to finish replication - latch.await(); - - // grace period to update the urledger metadata in zookeeper - LOG.info("Waiting to update the urledger metadata in zookeeper"); - - for (int index = 0; index < listOfLedgerHandle.size(); index++) { - verifyLedgerEnsembleMetadataAfterReplication(newBookieServer, - listOfLedgerHandle.get(index), - listOfReplicaIndex.get(index)); - } - } - - /** - * Test stopping replica service while replication in progress. Considering - * when there is an exception will shutdown Auditor and RW processes. After - * restarting should be able to finish the re-replication activities - */ - @Test - public void testStopWhileReplicationInProgress() throws Exception { - int numberOfLedgers = 2; - List listOfReplicaIndex = new ArrayList(); - List listOfLedgerHandle = createLedgersAndAddEntries( - numberOfLedgers, 5); - closeLedgers(listOfLedgerHandle); - LedgerHandle handle = listOfLedgerHandle.get(0); - BookieId replicaToKillAddr = handle.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - LOG.info("Killing Bookie:" + replicaToKillAddr); - - // Each ledger, there will be two events : create urLedger and after - // rereplication delete urLedger - CountDownLatch latch = new CountDownLatch(listOfLedgerHandle.size()); - for (int i = 0; i < listOfLedgerHandle.size(); i++) { - final String urLedgerZNode = getUrLedgerZNode(listOfLedgerHandle - .get(i)); - assertNull("UrLedger already exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - int replicaIndexInLedger = getReplicaIndexInLedger( - listOfLedgerHandle.get(i), replicaToKillAddr); - listOfReplicaIndex.add(replicaIndexInLedger); - } - - LOG.info("Killing Bookie :" + replicaToKillAddr); - killBookie(replicaToKillAddr); - - // waiting to publish urLedger znode by Auditor - latch.await(); - - // Again watching the urLedger znode to know the replication status - latch = new CountDownLatch(listOfLedgerHandle.size()); - for (LedgerHandle lh : listOfLedgerHandle) { - String urLedgerZNode = getUrLedgerZNode(lh); - LOG.info("Watching on urLedgerPath:" + urLedgerZNode - + " to know the status of rereplication process"); - assertNotNull("UrLedger doesn't exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - } - - // starting the replication service, so that he will be able to act as - // target bookie - startNewBookie(); - int newBookieIndex = lastBookieIndex(); - BookieServer newBookieServer = serverByIndex(newBookieIndex); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting to finish the replication of failed bookie : " - + replicaToKillAddr); - } - while (true) { - if (latch.getCount() < numberOfLedgers || latch.getCount() <= 0) { - stopReplicationService(); - LOG.info("Latch Count is:" + latch.getCount()); - break; - } - // grace period to take breath - Thread.sleep(1000); - } - - startReplicationService(); - - LOG.info("Waiting to finish rereplication processes"); - latch.await(); - - // grace period to update the urledger metadata in zookeeper - LOG.info("Waiting to update the urledger metadata in zookeeper"); - - for (int index = 0; index < listOfLedgerHandle.size(); index++) { - verifyLedgerEnsembleMetadataAfterReplication(newBookieServer, - listOfLedgerHandle.get(index), - listOfReplicaIndex.get(index)); - } - } - - /** - * Verify the published urledgers of deleted ledgers(those ledgers where - * deleted after publishing as urledgers by Auditor) should be cleared off - * by the newly selected replica bookie. - */ - @Test - public void testNoSuchLedgerExists() throws Exception { - List listOfLedgerHandle = createLedgersAndAddEntries(2, 5); - CountDownLatch latch = new CountDownLatch(listOfLedgerHandle.size()); - for (LedgerHandle lh : listOfLedgerHandle) { - assertNull("UrLedger already exists!", - watchUrLedgerNode(getUrLedgerZNode(lh), latch)); - } - BookieId replicaToKillAddr = listOfLedgerHandle.get(0) - .getLedgerMetadata().getAllEnsembles() - .get(0L).get(0); - killBookie(replicaToKillAddr); - replicaToKillAddr = listOfLedgerHandle.get(0) - .getLedgerMetadata().getAllEnsembles() - .get(0L).get(0); - killBookie(replicaToKillAddr); - // waiting to publish urLedger znode by Auditor - latch.await(); - - latch = new CountDownLatch(listOfLedgerHandle.size()); - for (LedgerHandle lh : listOfLedgerHandle) { - assertNotNull("UrLedger doesn't exists!", - watchUrLedgerNode(getUrLedgerZNode(lh), latch)); - } - - // delete ledgers - for (LedgerHandle lh : listOfLedgerHandle) { - bkc.deleteLedger(lh.getId()); - } - startNewBookie(); - - // waiting to delete published urledgers, since it doesn't exists - latch.await(); - - for (LedgerHandle lh : listOfLedgerHandle) { - assertNull("UrLedger still exists after rereplication", - watchUrLedgerNode(getUrLedgerZNode(lh), latch)); - } - } - - /** - * Test that if a empty ledger loses the bookie not in the quorum for entry 0, it will - * still be openable when it loses enough bookies to lose a whole quorum. - */ - @Test - public void testEmptyLedgerLosesQuorumEventually() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 2, 2, DigestType.CRC32, PASSWD); - CountDownLatch latch = new CountDownLatch(1); - String urZNode = getUrLedgerZNode(lh); - watchUrLedgerNode(urZNode, latch); - - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(2); - LOG.info("Killing last bookie, {}, in ensemble {}", replicaToKill, - lh.getLedgerMetadata().getAllEnsembles().get(0L)); - killBookie(replicaToKill); - startNewBookie(); - - getAuditor(10, TimeUnit.SECONDS).submitAuditTask().get(); // ensure auditor runs - - assertTrue("Should be marked as underreplicated", latch.await(5, TimeUnit.SECONDS)); - latch = new CountDownLatch(1); - Stat s = watchUrLedgerNode(urZNode, latch); // should be marked as replicated - if (s != null) { - assertTrue("Should be marked as replicated", latch.await(15, TimeUnit.SECONDS)); - } - - replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(1); - LOG.info("Killing second bookie, {}, in ensemble {}", replicaToKill, - lh.getLedgerMetadata().getAllEnsembles().get(0L)); - killBookie(replicaToKill); - - getAuditor(10, TimeUnit.SECONDS).submitAuditTask().get(); // ensure auditor runs - - assertTrue("Should be marked as underreplicated", latch.await(5, TimeUnit.SECONDS)); - latch = new CountDownLatch(1); - s = watchUrLedgerNode(urZNode, latch); // should be marked as replicated - - startNewBookie(); - getAuditor(10, TimeUnit.SECONDS).submitAuditTask().get(); // ensure auditor runs - - if (s != null) { - assertTrue("Should be marked as replicated", latch.await(20, TimeUnit.SECONDS)); - } - - // should be able to open ledger without issue - bkc.openLedger(lh.getId(), DigestType.CRC32, PASSWD); - } - - /** - * Test verifies bookie recovery, the host (recorded via ipaddress in - * ledgermetadata). - */ - @Test - public void testLedgerMetadataContainsIpAddressAsBookieID() - throws Exception { - stopBKCluster(); - bkc = new BookKeeperTestClient(baseClientConf); - // start bookie with useHostNameAsBookieID=false, as old bookie - ServerConfiguration serverConf1 = newServerConfiguration(); - // start 2 more bookies with useHostNameAsBookieID=true - ServerConfiguration serverConf2 = newServerConfiguration(); - serverConf2.setUseHostNameAsBookieID(true); - ServerConfiguration serverConf3 = newServerConfiguration(); - serverConf3.setUseHostNameAsBookieID(true); - startAndAddBookie(serverConf1); - startAndAddBookie(serverConf2); - startAndAddBookie(serverConf3); - - List listOfLedgerHandle = createLedgersAndAddEntries(1, 5); - LedgerHandle lh = listOfLedgerHandle.get(0); - int ledgerReplicaIndex = 0; - final SortedMap> ensembles = lh.getLedgerMetadata().getAllEnsembles(); - final List bkAddresses = ensembles.get(0L); - BookieId replicaToKillAddr = bkAddresses.get(0); - for (BookieId bookieSocketAddress : bkAddresses) { - if (!isCreatedFromIp(bookieSocketAddress)) { - replicaToKillAddr = bookieSocketAddress; - LOG.info("Kill bookie which has registered using hostname"); - break; - } - } - - final String urLedgerZNode = getUrLedgerZNode(lh); - ledgerReplicaIndex = getReplicaIndexInLedger(lh, replicaToKillAddr); - - CountDownLatch latch = new CountDownLatch(1); - assertNull("UrLedger already exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - - LOG.info("Killing Bookie :" + replicaToKillAddr); - killBookie(replicaToKillAddr); - - // waiting to publish urLedger znode by Auditor - latch.await(); - latch = new CountDownLatch(1); - LOG.info("Watching on urLedgerPath:" + urLedgerZNode - + " to know the status of rereplication process"); - assertNotNull("UrLedger doesn't exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - - // starting the replication service, so that he will be able to act as - // target bookie - ServerConfiguration serverConf = newServerConfiguration(); - serverConf.setUseHostNameAsBookieID(false); - startAndAddBookie(serverConf); - - int newBookieIndex = lastBookieIndex(); - BookieServer newBookieServer = serverByIndex(newBookieIndex); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting to finish the replication of failed bookie : " - + replicaToKillAddr); - } - latch.await(); - - // grace period to update the urledger metadata in zookeeper - LOG.info("Waiting to update the urledger metadata in zookeeper"); - - verifyLedgerEnsembleMetadataAfterReplication(newBookieServer, - listOfLedgerHandle.get(0), ledgerReplicaIndex); - - } - - /** - * Test verifies bookie recovery, the host (recorded via useHostName in - * ledgermetadata). - */ - @Test - public void testLedgerMetadataContainsHostNameAsBookieID() - throws Exception { - stopBKCluster(); - - bkc = new BookKeeperTestClient(baseClientConf); - // start bookie with useHostNameAsBookieID=false, as old bookie - ServerConfiguration serverConf1 = newServerConfiguration(); - // start 2 more bookies with useHostNameAsBookieID=true - ServerConfiguration serverConf2 = newServerConfiguration(); - serverConf2.setUseHostNameAsBookieID(true); - ServerConfiguration serverConf3 = newServerConfiguration(); - serverConf3.setUseHostNameAsBookieID(true); - startAndAddBookie(serverConf1); - startAndAddBookie(serverConf2); - startAndAddBookie(serverConf3); - - List listOfLedgerHandle = createLedgersAndAddEntries(1, 5); - LedgerHandle lh = listOfLedgerHandle.get(0); - int ledgerReplicaIndex = 0; - final SortedMap> ensembles = lh.getLedgerMetadata().getAllEnsembles(); - final List bkAddresses = ensembles.get(0L); - BookieId replicaToKillAddr = bkAddresses.get(0); - for (BookieId bookieSocketAddress : bkAddresses) { - if (isCreatedFromIp(bookieSocketAddress)) { - replicaToKillAddr = bookieSocketAddress; - LOG.info("Kill bookie which has registered using ipaddress"); - break; - } - } - - final String urLedgerZNode = getUrLedgerZNode(lh); - ledgerReplicaIndex = getReplicaIndexInLedger(lh, replicaToKillAddr); - - CountDownLatch latch = new CountDownLatch(1); - assertNull("UrLedger already exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - - LOG.info("Killing Bookie :" + replicaToKillAddr); - killBookie(replicaToKillAddr); - - // waiting to publish urLedger znode by Auditor - latch.await(); - latch = new CountDownLatch(1); - LOG.info("Watching on urLedgerPath:" + urLedgerZNode - + " to know the status of rereplication process"); - assertNotNull("UrLedger doesn't exists!", - watchUrLedgerNode(urLedgerZNode, latch)); - - // creates new bkclient - bkc = new BookKeeperTestClient(baseClientConf); - // starting the replication service, so that he will be able to act as - // target bookie - ServerConfiguration serverConf = newServerConfiguration(); - serverConf.setUseHostNameAsBookieID(true); - startAndAddBookie(serverConf); - - int newBookieIndex = lastBookieIndex(); - BookieServer newBookieServer = serverByIndex(newBookieIndex); - - if (LOG.isDebugEnabled()) { - LOG.debug("Waiting to finish the replication of failed bookie : " - + replicaToKillAddr); - } - latch.await(); - - // grace period to update the urledger metadata in zookeeper - LOG.info("Waiting to update the urledger metadata in zookeeper"); - - verifyLedgerEnsembleMetadataAfterReplication(newBookieServer, - listOfLedgerHandle.get(0), ledgerReplicaIndex); - - } - - private int getReplicaIndexInLedger(LedgerHandle lh, BookieId replicaToKill) { - SortedMap> ensembles = lh.getLedgerMetadata().getAllEnsembles(); - int ledgerReplicaIndex = -1; - for (BookieId addr : ensembles.get(0L)) { - ++ledgerReplicaIndex; - if (addr.equals(replicaToKill)) { - break; - } - } - return ledgerReplicaIndex; - } - - private void verifyLedgerEnsembleMetadataAfterReplication( - BookieServer newBookieServer, LedgerHandle lh, - int ledgerReplicaIndex) throws Exception { - LedgerHandle openLedger = bkc - .openLedger(lh.getId(), digestType, PASSWD); - - BookieId inetSocketAddress = openLedger.getLedgerMetadata().getAllEnsembles().get(0L) - .get(ledgerReplicaIndex); - assertEquals("Rereplication has been failed and ledgerReplicaIndex :" - + ledgerReplicaIndex, newBookieServer.getBookieId(), - inetSocketAddress); - openLedger.close(); - } - - private void closeLedgers(List listOfLedgerHandle) - throws InterruptedException, BKException { - for (LedgerHandle lh : listOfLedgerHandle) { - lh.close(); - } - } - - private List createLedgersAndAddEntries(int numberOfLedgers, - int numberOfEntries) throws InterruptedException, BKException { - List listOfLedgerHandle = new ArrayList( - numberOfLedgers); - for (int index = 0; index < numberOfLedgers; index++) { - LedgerHandle lh = bkc.createLedger(3, 3, digestType, PASSWD); - listOfLedgerHandle.add(lh); - for (int i = 0; i < numberOfEntries; i++) { - lh.addEntry(data); - } - } - return listOfLedgerHandle; - } - - private String getUrLedgerZNode(LedgerHandle lh) { - return ZkLedgerUnderreplicationManager.getUrLedgerZnode( - underreplicatedPath, lh.getId()); - } - - private Stat watchUrLedgerNode(final String znode, - final CountDownLatch latch) throws KeeperException, - InterruptedException { - return zkc.exists(znode, new Watcher() { - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.NodeDeleted) { - LOG.info("Received Ledger rereplication completion event :" - + event.getType()); - latch.countDown(); - } - if (event.getType() == EventType.NodeCreated) { - LOG.info("Received urLedger publishing event :" - + event.getType()); - latch.countDown(); - } - } - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieLedgerIndexTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieLedgerIndexTest.java deleted file mode 100644 index f4483917980..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieLedgerIndexTest.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.meta.AbstractZkLedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.ZkLayoutManager; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.replication.ReplicationException.BKAuditException; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.zookeeper.KeeperException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests verifies bookie vs ledger mapping generating by the BookieLedgerIndexer. - */ -public class BookieLedgerIndexTest extends BookKeeperClusterTestCase { - - // Depending on the taste, select the amount of logging - // by decommenting one of the two lines below - // private final static Logger LOG = Logger.getRootLogger(); - private static final Logger LOG = LoggerFactory - .getLogger(BookieLedgerIndexTest.class); - - private Random rng; // Random Number Generator - private ArrayList entries; // generated entries - private final DigestType digestType = DigestType.CRC32; - private int numberOfLedgers = 3; - private List ledgerList; - private LedgerManagerFactory newLedgerManagerFactory; - private LedgerManager ledgerManager; - - public BookieLedgerIndexTest() - throws IOException, KeeperException, InterruptedException { - this("org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"); - } - - BookieLedgerIndexTest(String ledgerManagerFactory) - throws IOException, KeeperException, InterruptedException { - super(3); - LOG.info("Running test case using ledger manager : " - + ledgerManagerFactory); - // set ledger manager name - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - @Before - public void setUp() throws Exception { - super.setUp(); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - rng = new Random(System.currentTimeMillis()); // Initialize the Random - // Number Generator - entries = new ArrayList(); // initialize the entries list - ledgerList = new ArrayList(3); - // initialize ledger manager - newLedgerManagerFactory = AbstractZkLedgerManagerFactory.newLedgerManagerFactory( - baseConf, - new ZkLayoutManager(zkc, - ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf), ZkUtils.getACLs(baseConf))); - - ledgerManager = newLedgerManagerFactory.newLedgerManager(); - } - - @After - public void tearDown() throws Exception { - super.tearDown(); - if (null != newLedgerManagerFactory) { - newLedgerManagerFactory.close(); - newLedgerManagerFactory = null; - } - if (null != ledgerManager) { - ledgerManager.close(); - ledgerManager = null; - } - } - - /** - * Verify the bookie-ledger mapping with minimum number of bookies and few - * ledgers. - */ - @Test - public void testSimpleBookieLedgerMapping() throws Exception { - - for (int i = 0; i < numberOfLedgers; i++) { - createAndAddEntriesToLedger().close(); - } - - BookieLedgerIndexer bookieLedgerIndex = new BookieLedgerIndexer( - ledgerManager); - - Map> bookieToLedgerIndex = bookieLedgerIndex - .getBookieToLedgerIndex(); - - assertEquals("Missed few bookies in the bookie-ledger mapping!", 3, - bookieToLedgerIndex.size()); - Collection> bk2ledgerEntry = bookieToLedgerIndex.values(); - for (Set ledgers : bk2ledgerEntry) { - assertEquals("Missed few ledgers in the bookie-ledger mapping!", 3, - ledgers.size()); - for (Long ledgerId : ledgers) { - assertTrue("Unknown ledger-bookie mapping", ledgerList - .contains(ledgerId)); - } - } - } - - /** - * Verify ledger index with failed bookies and throws exception. - */ - @SuppressWarnings("deprecation") - @Test - public void testWithoutZookeeper() throws Exception { - // This test case is for ledger metadata that stored in ZooKeeper. As - // far as MSLedgerManagerFactory, ledger metadata are stored in other - // storage. So this test is not suitable for MSLedgerManagerFactory. - if (newLedgerManagerFactory instanceof org.apache.bookkeeper.meta.MSLedgerManagerFactory) { - return; - } - - for (int i = 0; i < numberOfLedgers; i++) { - createAndAddEntriesToLedger().close(); - } - - BookieLedgerIndexer bookieLedgerIndex = new BookieLedgerIndexer( - ledgerManager); - stopZKCluster(); - try { - bookieLedgerIndex.getBookieToLedgerIndex(); - fail("Must throw exception as zookeeper are not running!"); - } catch (BKAuditException bkAuditException) { - // expected behaviour - } - } - - /** - * Verify indexing with multiple ensemble reformation. - */ - @Test - public void testEnsembleReformation() throws Exception { - try { - LedgerHandle lh1 = createAndAddEntriesToLedger(); - LedgerHandle lh2 = createAndAddEntriesToLedger(); - - startNewBookie(); - shutdownBookie(lastBookieIndex() - 1); - - // add few more entries after ensemble reformation - for (int i = 0; i < 10; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(Integer.MAX_VALUE)); - entry.position(0); - - entries.add(entry.array()); - lh1.addEntry(entry.array()); - lh2.addEntry(entry.array()); - } - - BookieLedgerIndexer bookieLedgerIndex = new BookieLedgerIndexer( - ledgerManager); - - Map> bookieToLedgerIndex = bookieLedgerIndex - .getBookieToLedgerIndex(); - assertEquals("Missed few bookies in the bookie-ledger mapping!", 4, - bookieToLedgerIndex.size()); - Collection> bk2ledgerEntry = bookieToLedgerIndex.values(); - for (Set ledgers : bk2ledgerEntry) { - assertEquals( - "Missed few ledgers in the bookie-ledger mapping!", 2, - ledgers.size()); - for (Long ledgerNode : ledgers) { - assertTrue("Unknown ledger-bookie mapping", ledgerList - .contains(ledgerNode)); - } - } - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - private void shutdownBookie(int bkShutdownIndex) throws Exception { - killBookie(bkShutdownIndex); - } - - private LedgerHandle createAndAddEntriesToLedger() throws BKException, - InterruptedException { - int numEntriesToWrite = 20; - // Create a ledger - LedgerHandle lh = bkc.createLedger(digestType, "admin".getBytes()); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(Integer.MAX_VALUE)); - entry.position(0); - - entries.add(entry.array()); - lh.addEntry(entry.array()); - } - ledgerList.add(lh.getId()); - return lh; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/ReplicationTestUtil.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/ReplicationTestUtil.java deleted file mode 100644 index e36955a0c29..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/ReplicationTestUtil.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import java.util.List; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooKeeper; - -/** - * Utility class for replication tests. - */ -public class ReplicationTestUtil { - - /** - * Checks whether ledger is in under-replication. - */ - public static boolean isLedgerInUnderReplication(ZooKeeper zkc, long id, - String basePath) throws KeeperException, InterruptedException { - List children; - try { - children = zkc.getChildren(basePath, true); - } catch (KeeperException.NoNodeException nne) { - return false; - } - - boolean isMatched = false; - for (String child : children) { - if (child.startsWith("urL") && child.contains(String.valueOf(id))) { - isMatched = true; - break; - } else { - String path = basePath + '/' + child; - try { - if (zkc.getChildren(path, false).size() > 0) { - isMatched = isLedgerInUnderReplication(zkc, id, path); - } - } catch (KeeperException.NoNodeException nne) { - return false; - } - } - - } - return isMatched; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestAutoRecoveryAlongWithBookieServers.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestAutoRecoveryAlongWithBookieServers.java deleted file mode 100644 index 9506ba02772..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestAutoRecoveryAlongWithBookieServers.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Enumeration; -import java.util.List; -import java.util.Map.Entry; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.junit.Before; -import org.junit.Test; - -/** - * Test auto recovery. - */ -public class TestAutoRecoveryAlongWithBookieServers extends - BookKeeperClusterTestCase { - - private String basePath = ""; - - public TestAutoRecoveryAlongWithBookieServers() { - super(3); - setAutoRecoveryEnabled(true); - - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - - basePath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseClientConf) + '/' - + BookKeeperConstants.UNDER_REPLICATION_NODE - + BookKeeperConstants.DEFAULT_ZK_LEDGERS_ROOT_PATH; - } - - /** - * Tests that the auto recovery service along with Bookie servers itself. - */ - @Test - public void testAutoRecoveryAlongWithBookieServers() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - "testpasswd".getBytes()); - byte[] testData = "testBuiltAutoRecovery".getBytes(); - - for (int i = 0; i < 10; i++) { - lh.addEntry(testData); - } - lh.close(); - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - killBookie(replicaToKill); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), - basePath)) { - Thread.sleep(100); - } - - // Killing all bookies except newly replicated bookie - for (Entry> entry : - lh.getLedgerMetadata().getAllEnsembles().entrySet()) { - List bookies = entry.getValue(); - for (BookieId bookie : bookies) { - if (bookie.equals(newBkAddr)) { - continue; - } - killBookie(bookie); - } - } - - // Should be able to read the entries from 0-9 - LedgerHandle lhs = bkc.openLedgerNoRecovery(lh.getId(), - BookKeeper.DigestType.CRC32, "testpasswd".getBytes()); - Enumeration entries = lhs.readEntries(0, 9); - assertTrue("Should have the elements", entries.hasMoreElements()); - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertEquals("testBuiltAutoRecovery", new String(entry.getEntry())); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestLedgerUnderreplicationManager.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestLedgerUnderreplicationManager.java deleted file mode 100644 index 33cdd24c1c3..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestLedgerUnderreplicationManager.java +++ /dev/null @@ -1,881 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.replication; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.protobuf.TextFormat; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import lombok.Cleanup; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.AbstractZkLedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.ZkLayoutManager; -import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.DNS; -import org.apache.bookkeeper.proto.DataFormats.UnderreplicatedLedgerFormat; -import org.apache.bookkeeper.replication.ReplicationException.UnavailableException; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.commons.lang.StringUtils; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the zookeeper implementation of the ledger replication manager. - */ -public class TestLedgerUnderreplicationManager { - static final Logger LOG = LoggerFactory.getLogger(TestLedgerUnderreplicationManager.class); - - ZooKeeperUtil zkUtil = null; - - ServerConfiguration conf = null; - ExecutorService executor = null; - LedgerManagerFactory lmf1 = null; - LedgerManagerFactory lmf2 = null; - ZooKeeper zkc1 = null; - ZooKeeper zkc2 = null; - - String basePath; - String urLedgerPath; - boolean isLedgerReplicationDisabled = true; - - @Before - public void setupZooKeeper() throws Exception { - zkUtil = new ZooKeeperUtil(); - zkUtil.startCluster(); - - conf = TestBKConfiguration.newServerConfiguration(); - conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - executor = Executors.newCachedThreadPool(); - - zkc1 = ZooKeeperClient.newBuilder() - .connectString(zkUtil.getZooKeeperConnectString()) - .sessionTimeoutMs(10000) - .build(); - zkc2 = ZooKeeperClient.newBuilder() - .connectString(zkUtil.getZooKeeperConnectString()) - .sessionTimeoutMs(10000) - .build(); - - String zkLedgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf); - - basePath = zkLedgersRootPath + '/' - + BookKeeperConstants.UNDER_REPLICATION_NODE; - urLedgerPath = basePath - + BookKeeperConstants.DEFAULT_ZK_LEDGERS_ROOT_PATH; - - lmf1 = AbstractZkLedgerManagerFactory.newLedgerManagerFactory( - conf, - new ZkLayoutManager( - zkc1, - zkLedgersRootPath, - ZkUtils.getACLs(conf))); - lmf2 = AbstractZkLedgerManagerFactory.newLedgerManagerFactory( - conf, - new ZkLayoutManager( - zkc2, - zkLedgersRootPath, - ZkUtils.getACLs(conf))); - - } - - @After - public void teardownZooKeeper() throws Exception { - if (zkUtil != null) { - zkUtil.killCluster(); - zkUtil = null; - } - if (executor != null) { - executor = null; - } - if (zkc1 != null) { - zkc1.close(); - zkc1 = null; - } - if (zkc2 != null) { - zkc2.close(); - zkc2 = null; - } - if (lmf1 != null) { - lmf1.close(); - lmf1 = null; - } - if (lmf2 != null) { - lmf2.close(); - lmf2 = null; - } - } - - private Future getLedgerToReplicate(final LedgerUnderreplicationManager m) { - return executor.submit(new Callable() { - public Long call() { - try { - return m.getLedgerToRereplicate(); - } catch (Exception e) { - LOG.error("Error getting ledger id", e); - return -1L; - } - } - }); - } - - /** - * Test basic interactions with the ledger underreplication - * manager. - * Mark some ledgers as underreplicated. - * Ensure that getLedgerToReplicate will block until it a ledger - * becomes available. - */ - @Test - public void testBasicInteraction() throws Exception { - Set ledgers = new HashSet(); - ledgers.add(0xdeadbeefL); - ledgers.add(0xbeefcafeL); - ledgers.add(0xffffbeefL); - ledgers.add(0xfacebeefL); - String missingReplica = "localhost:3181"; - - int count = 0; - LedgerUnderreplicationManager m = lmf1.newLedgerUnderreplicationManager(); - Iterator iter = ledgers.iterator(); - while (iter.hasNext()) { - m.markLedgerUnderreplicated(iter.next(), missingReplica); - count++; - } - - List> futures = new ArrayList>(); - for (int i = 0; i < count; i++) { - futures.add(getLedgerToReplicate(m)); - } - - for (Future f : futures) { - Long l = f.get(5, TimeUnit.SECONDS); - assertTrue(ledgers.remove(l)); - } - - Future f = getLedgerToReplicate(m); - try { - f.get(1, TimeUnit.SECONDS); - fail("Shouldn't be able to find a ledger to replicate"); - } catch (TimeoutException te) { - // correct behaviour - } - Long newl = 0xfefefefefefeL; - m.markLedgerUnderreplicated(newl, missingReplica); - assertEquals("Should have got the one just added", newl, f.get(5, TimeUnit.SECONDS)); - } - - /** - * Test locking for ledger unreplication manager. - * If there's only one ledger marked for rereplication, - * and one client has it, it should be locked; another - * client shouldn't be able to get it. If the first client dies - * however, the second client should be able to get it. - */ - @Test - public void testLocking() throws Exception { - String missingReplica = "localhost:3181"; - - LedgerUnderreplicationManager m1 = lmf1.newLedgerUnderreplicationManager(); - LedgerUnderreplicationManager m2 = lmf2.newLedgerUnderreplicationManager(); - - Long ledger = 0xfeadeefdacL; - m1.markLedgerUnderreplicated(ledger, missingReplica); - Future f = getLedgerToReplicate(m1); - Long l = f.get(5, TimeUnit.SECONDS); - assertEquals("Should be the ledger I just marked", ledger, l); - - f = getLedgerToReplicate(m2); - try { - f.get(1, TimeUnit.SECONDS); - fail("Shouldn't be able to find a ledger to replicate"); - } catch (TimeoutException te) { - // correct behaviour - } - zkc1.close(); // should kill the lock - zkc1 = null; - - l = f.get(5, TimeUnit.SECONDS); - assertEquals("Should be the ledger I marked", ledger, l); - } - - - /** - * Test that when a ledger has been marked as replicated, it - * will not be offered to anther client. - * This test checked that by marking two ledgers, and acquiring - * them on a single client. It marks one as replicated and then - * the client is killed. We then check that another client can - * acquire a ledger, and that it's not the one that was previously - * marked as replicated. - */ - @Test - public void testMarkingAsReplicated() throws Exception { - String missingReplica = "localhost:3181"; - - LedgerUnderreplicationManager m1 = lmf1.newLedgerUnderreplicationManager(); - LedgerUnderreplicationManager m2 = lmf2.newLedgerUnderreplicationManager(); - - Long ledgerA = 0xfeadeefdacL; - Long ledgerB = 0xdefadebL; - m1.markLedgerUnderreplicated(ledgerA, missingReplica); - m1.markLedgerUnderreplicated(ledgerB, missingReplica); - - Future fA = getLedgerToReplicate(m1); - Future fB = getLedgerToReplicate(m1); - - Long lA = fA.get(5, TimeUnit.SECONDS); - Long lB = fB.get(5, TimeUnit.SECONDS); - - assertTrue("Should be the ledgers I just marked", - (lA.equals(ledgerA) && lB.equals(ledgerB)) - || (lA.equals(ledgerB) && lB.equals(ledgerA))); - - Future f = getLedgerToReplicate(m2); - try { - f.get(1, TimeUnit.SECONDS); - fail("Shouldn't be able to find a ledger to replicate"); - } catch (TimeoutException te) { - // correct behaviour - } - m1.markLedgerReplicated(lA); - zkc1.close(); // should kill the lock - zkc1 = null; - - Long l = f.get(5, TimeUnit.SECONDS); - assertEquals("Should be the ledger I marked", lB, l); - } - - /** - * Test releasing of a ledger - * A ledger is released when a client decides it does not want - * to replicate it (or cannot at the moment). - * When a client releases a previously acquired ledger, another - * client should then be able to acquire it. - */ - @Test - public void testRelease() throws Exception { - String missingReplica = "localhost:3181"; - - LedgerUnderreplicationManager m1 = lmf1.newLedgerUnderreplicationManager(); - LedgerUnderreplicationManager m2 = lmf2.newLedgerUnderreplicationManager(); - - Long ledgerA = 0xfeadeefdacL; - Long ledgerB = 0xdefadebL; - m1.markLedgerUnderreplicated(ledgerA, missingReplica); - m1.markLedgerUnderreplicated(ledgerB, missingReplica); - - Future fA = getLedgerToReplicate(m1); - Future fB = getLedgerToReplicate(m1); - - Long lA = fA.get(5, TimeUnit.SECONDS); - Long lB = fB.get(5, TimeUnit.SECONDS); - - assertTrue("Should be the ledgers I just marked", - (lA.equals(ledgerA) && lB.equals(ledgerB)) - || (lA.equals(ledgerB) && lB.equals(ledgerA))); - - Future f = getLedgerToReplicate(m2); - try { - f.get(1, TimeUnit.SECONDS); - fail("Shouldn't be able to find a ledger to replicate"); - } catch (TimeoutException te) { - // correct behaviour - } - m1.markLedgerReplicated(lA); - m1.releaseUnderreplicatedLedger(lB); - - Long l = f.get(5, TimeUnit.SECONDS); - assertEquals("Should be the ledger I marked", lB, l); - } - - /** - * Test that when a failure occurs on a ledger, while the ledger - * is already being rereplicated, the ledger will still be in the - * under replicated ledger list when first rereplicating client marks - * it as replicated. - */ - @Test - public void testManyFailures() throws Exception { - String missingReplica1 = "localhost:3181"; - String missingReplica2 = "localhost:3182"; - - LedgerUnderreplicationManager m1 = lmf1.newLedgerUnderreplicationManager(); - - Long ledgerA = 0xfeadeefdacL; - m1.markLedgerUnderreplicated(ledgerA, missingReplica1); - - Future fA = getLedgerToReplicate(m1); - Long lA = fA.get(5, TimeUnit.SECONDS); - - m1.markLedgerUnderreplicated(ledgerA, missingReplica2); - - assertEquals("Should be the ledger I just marked", - lA, ledgerA); - m1.markLedgerReplicated(lA); - - Future f = getLedgerToReplicate(m1); - lA = f.get(5, TimeUnit.SECONDS); - assertEquals("Should be the ledger I had marked previously", - lA, ledgerA); - } - - /** - * If replicationworker has acquired lock on it, then - * getReplicationWorkerIdRereplicatingLedger should return - * ReplicationWorkerId (BookieId) of the ReplicationWorker that is holding - * lock. If lock for the underreplicated ledger is not yet acquired or if it - * is released then it is supposed to return null. - * - * @throws Exception - */ - @Test - public void testGetReplicationWorkerIdRereplicatingLedger() throws Exception { - String missingReplica1 = "localhost:3181"; - String missingReplica2 = "localhost:3182"; - - LedgerUnderreplicationManager m1 = lmf1.newLedgerUnderreplicationManager(); - - Long ledgerA = 0xfeadeefdacL; - m1.markLedgerUnderreplicated(ledgerA, missingReplica1); - m1.markLedgerUnderreplicated(ledgerA, missingReplica2); - - // lock is not yet acquired so replicationWorkerIdRereplicatingLedger - // should - assertEquals("ReplicationWorkerId of the lock", null, m1.getReplicationWorkerIdRereplicatingLedger(ledgerA)); - - Future fA = getLedgerToReplicate(m1); - Long lA = fA.get(5, TimeUnit.SECONDS); - assertEquals("Should be the ledger that was just marked", lA, ledgerA); - - /* - * ZkLedgerUnderreplicationManager.getLockData uses - * DNS.getDefaultHost("default") as the bookieId. - * - */ - assertEquals("ReplicationWorkerId of the lock", DNS.getDefaultHost("default"), - m1.getReplicationWorkerIdRereplicatingLedger(ledgerA)); - - m1.markLedgerReplicated(lA); - - assertEquals("ReplicationWorkerId of the lock", null, m1.getReplicationWorkerIdRereplicatingLedger(ledgerA)); - } - - /** - * Test that when a ledger is marked as underreplicated with - * the same missing replica twice, only marking as replicated - * will be enough to remove it from the list. - */ - @Test - public void test2reportSame() throws Exception { - String missingReplica1 = "localhost:3181"; - - LedgerUnderreplicationManager m1 = lmf1.newLedgerUnderreplicationManager(); - LedgerUnderreplicationManager m2 = lmf2.newLedgerUnderreplicationManager(); - - Long ledgerA = 0xfeadeefdacL; - m1.markLedgerUnderreplicated(ledgerA, missingReplica1); - m2.markLedgerUnderreplicated(ledgerA, missingReplica1); - - // verify duplicate missing replica - UnderreplicatedLedgerFormat.Builder builderA = UnderreplicatedLedgerFormat - .newBuilder(); - String znode = getUrLedgerZnode(ledgerA); - byte[] data = zkc1.getData(znode, false, null); - TextFormat.merge(new String(data, Charset.forName("UTF-8")), builderA); - List replicaList = builderA.getReplicaList(); - assertEquals("Published duplicate missing replica : " + replicaList, 1, - replicaList.size()); - assertTrue("Published duplicate missing replica : " + replicaList, - replicaList.contains(missingReplica1)); - - Future fA = getLedgerToReplicate(m1); - Long lA = fA.get(5, TimeUnit.SECONDS); - - assertEquals("Should be the ledger I just marked", - lA, ledgerA); - m1.markLedgerReplicated(lA); - - Future f = getLedgerToReplicate(m2); - try { - f.get(1, TimeUnit.SECONDS); - fail("Shouldn't be able to find a ledger to replicate"); - } catch (TimeoutException te) { - // correct behaviour - } - } - - /** - * Test that multiple LedgerUnderreplicationManagers should be able to take - * lock and release for same ledger. - */ - @Test - public void testMultipleManagersShouldBeAbleToTakeAndReleaseLock() - throws Exception { - String missingReplica1 = "localhost:3181"; - final LedgerUnderreplicationManager m1 = lmf1 - .newLedgerUnderreplicationManager(); - final LedgerUnderreplicationManager m2 = lmf2 - .newLedgerUnderreplicationManager(); - Long ledgerA = 0xfeadeefdacL; - m1.markLedgerUnderreplicated(ledgerA, missingReplica1); - final int iterationCount = 100; - final CountDownLatch latch1 = new CountDownLatch(iterationCount); - final CountDownLatch latch2 = new CountDownLatch(iterationCount); - Thread thread1 = new Thread() { - @Override - public void run() { - takeLedgerAndRelease(m1, latch1, iterationCount); - } - }; - - Thread thread2 = new Thread() { - @Override - public void run() { - takeLedgerAndRelease(m2, latch2, iterationCount); - } - }; - thread1.start(); - thread2.start(); - - // wait until at least one thread completed - while (!latch1.await(50, TimeUnit.MILLISECONDS) - && !latch2.await(50, TimeUnit.MILLISECONDS)) { - Thread.sleep(50); - } - - m1.close(); - m2.close(); - - // After completing 'lock acquire,release' job, it should notify below - // wait - latch1.await(); - latch2.await(); - } - - /** - * Test verifies failures of bookies which are resembling each other. - * - *

BK servers named like********************************************* - * 1.cluster.com, 2.cluster.com, 11.cluster.com, 12.cluster.com - * ******************************************************************* - * - *

BKserver IP:HOST like********************************************* - * localhost:3181, localhost:318, localhost:31812 - * ******************************************************************* - */ - @Test - public void testMarkSimilarMissingReplica() throws Exception { - List missingReplica = new ArrayList(); - missingReplica.add("localhost:3181"); - missingReplica.add("localhost:318"); - missingReplica.add("localhost:31812"); - missingReplica.add("1.cluster.com"); - missingReplica.add("2.cluster.com"); - missingReplica.add("11.cluster.com"); - missingReplica.add("12.cluster.com"); - verifyMarkLedgerUnderreplicated(missingReplica); - } - - /** - * Test multiple bookie failures for a ledger and marked as underreplicated - * one after another. - */ - @Test - public void testManyFailuresInAnEnsemble() throws Exception { - List missingReplica = new ArrayList(); - missingReplica.add("localhost:3181"); - missingReplica.add("localhost:3182"); - verifyMarkLedgerUnderreplicated(missingReplica); - } - - /** - * Test disabling the ledger re-replication. After disabling, it will not be - * able to getLedgerToRereplicate(). This calls will enter into infinite - * waiting until enabling rereplication process - */ - @Test - public void testDisableLedegerReplication() throws Exception { - final LedgerUnderreplicationManager replicaMgr = lmf1 - .newLedgerUnderreplicationManager(); - - // simulate few urLedgers before disabling - final Long ledgerA = 0xfeadeefdacL; - final String missingReplica = "localhost:3181"; - - // disabling replication - replicaMgr.disableLedgerReplication(); - LOG.info("Disabled Ledeger Replication"); - - try { - replicaMgr.markLedgerUnderreplicated(ledgerA, missingReplica); - } catch (UnavailableException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Unexpected exception while marking urLedger", e); - } - fail("Unexpected exception while marking urLedger" + e.getMessage()); - } - - Future fA = getLedgerToReplicate(replicaMgr); - try { - fA.get(1, TimeUnit.SECONDS); - fail("Shouldn't be able to find a ledger to replicate"); - } catch (TimeoutException te) { - // expected behaviour, as the replication is disabled - isLedgerReplicationDisabled = false; - } - - assertTrue("Ledger replication is not disabled!", - !isLedgerReplicationDisabled); - } - - /** - * Test enabling the ledger re-replication. After enableLedegerReplication, - * should continue getLedgerToRereplicate() task - */ - @Test - public void testEnableLedgerReplication() throws Exception { - isLedgerReplicationDisabled = true; - final LedgerUnderreplicationManager replicaMgr = lmf1 - .newLedgerUnderreplicationManager(); - - // simulate few urLedgers before disabling - final Long ledgerA = 0xfeadeefdacL; - final String missingReplica = "localhost:3181"; - try { - replicaMgr.markLedgerUnderreplicated(ledgerA, missingReplica); - } catch (UnavailableException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Unexpected exception while marking urLedger", e); - } - fail("Unexpected exception while marking urLedger" + e.getMessage()); - } - - // disabling replication - replicaMgr.disableLedgerReplication(); - if (LOG.isDebugEnabled()) { - LOG.debug("Disabled Ledeger Replication"); - } - - String znodeA = getUrLedgerZnode(ledgerA); - final CountDownLatch znodeLatch = new CountDownLatch(2); - String urledgerA = StringUtils.substringAfterLast(znodeA, "/"); - String urLockLedgerA = basePath + "/locks/" + urledgerA; - zkc1.exists(urLockLedgerA, new Watcher(){ - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.NodeCreated) { - znodeLatch.countDown(); - if (LOG.isDebugEnabled()) { - LOG.debug("Recieved node creation event for the zNodePath:" - + event.getPath()); - } - } - - }}); - // getLedgerToRereplicate is waiting until enable rereplication - Thread thread1 = new Thread() { - @Override - public void run() { - try { - Long lA = replicaMgr.getLedgerToRereplicate(); - assertEquals("Should be the ledger I just marked", lA, - ledgerA); - isLedgerReplicationDisabled = false; - znodeLatch.countDown(); - } catch (UnavailableException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Unexpected exception while marking urLedger", e); - } - isLedgerReplicationDisabled = false; - } - } - }; - thread1.start(); - - try { - assertFalse("shouldn't complete", znodeLatch.await(1, TimeUnit.SECONDS)); - assertTrue("Ledger replication is not disabled!", - isLedgerReplicationDisabled); - assertEquals("Failed to disable ledger replication!", 2, znodeLatch - .getCount()); - - replicaMgr.enableLedgerReplication(); - znodeLatch.await(5, TimeUnit.SECONDS); - if (LOG.isDebugEnabled()) { - LOG.debug("Enabled Ledeger Replication"); - } - assertTrue("Ledger replication is not disabled!", - !isLedgerReplicationDisabled); - assertEquals("Failed to disable ledger replication!", 0, znodeLatch - .getCount()); - } finally { - thread1.interrupt(); - } - } - - /** - * Test that the hierarchy gets cleaned up as ledgers - * are marked as fully replicated. - */ - @Test - public void testHierarchyCleanup() throws Exception { - final LedgerUnderreplicationManager replicaMgr = lmf1 - .newLedgerUnderreplicationManager(); - // 4 ledgers, 2 in the same hierarchy - long[] ledgers = { 0x00000000deadbeefL, 0x00000000deadbeeeL, - 0x00000000beefcafeL, 0x00000000cafed00dL }; - - for (long l : ledgers) { - replicaMgr.markLedgerUnderreplicated(l, "localhost:3181"); - } - // can't simply test top level as we are limited to ledger - // ids no larger than an int - String testPath = urLedgerPath + "/0000/0000"; - List children = zkc1.getChildren(testPath, false); - assertEquals("Wrong number of hierarchies", 3, children.size()); - - int marked = 0; - while (marked < 3) { - long l = replicaMgr.getLedgerToRereplicate(); - if (l != ledgers[0]) { - replicaMgr.markLedgerReplicated(l); - marked++; - } else { - replicaMgr.releaseUnderreplicatedLedger(l); - } - } - children = zkc1.getChildren(testPath, false); - assertEquals("Wrong number of hierarchies", 1, children.size()); - - long l = replicaMgr.getLedgerToRereplicate(); - assertEquals("Got wrong ledger", ledgers[0], l); - replicaMgr.markLedgerReplicated(l); - - children = zkc1.getChildren(urLedgerPath, false); - assertEquals("All hierarchies should be cleaned up", 0, children.size()); - } - - /** - * Test that as the hierarchy gets cleaned up, it doesn't interfere - * with the marking of other ledgers as underreplicated. - */ - @Test - public void testHierarchyCleanupInterference() throws Exception { - final LedgerUnderreplicationManager replicaMgr1 = lmf1 - .newLedgerUnderreplicationManager(); - final LedgerUnderreplicationManager replicaMgr2 = lmf2 - .newLedgerUnderreplicationManager(); - - final int iterations = 100; - final AtomicBoolean threadFailed = new AtomicBoolean(false); - Thread markUnder = new Thread() { - public void run() { - long l = 1; - try { - for (int i = 0; i < iterations; i++) { - replicaMgr1.markLedgerUnderreplicated(l, "localhost:3181"); - l += 10000; - } - } catch (Exception e) { - LOG.error("markUnder Thread failed with exception", e); - threadFailed.set(true); - return; - } - } - }; - final AtomicInteger processed = new AtomicInteger(0); - Thread markRepl = new Thread() { - public void run() { - try { - for (int i = 0; i < iterations; i++) { - long l = replicaMgr2.getLedgerToRereplicate(); - replicaMgr2.markLedgerReplicated(l); - processed.incrementAndGet(); - } - } catch (Exception e) { - LOG.error("markRepl Thread failed with exception", e); - threadFailed.set(true); - return; - } - } - }; - markRepl.setDaemon(true); - markUnder.setDaemon(true); - - markRepl.start(); - markUnder.start(); - markUnder.join(); - assertFalse("Thread failed to complete", threadFailed.get()); - - int lastProcessed = 0; - while (true) { - markRepl.join(10000); - if (!markRepl.isAlive()) { - break; - } - assertFalse("markRepl thread not progressing", lastProcessed == processed.get()); - } - assertFalse("Thread failed to complete", threadFailed.get()); - - List children = zkc1.getChildren(urLedgerPath, false); - for (String s : children) { - LOG.info("s: {}", s); - } - assertEquals("All hierarchies should be cleaned up", 0, children.size()); - } - - @Test - public void testCheckAllLedgersCTime() throws Exception { - @Cleanup - LedgerUnderreplicationManager underReplicaMgr1 = lmf1.newLedgerUnderreplicationManager(); - @Cleanup - LedgerUnderreplicationManager underReplicaMgr2 = lmf2.newLedgerUnderreplicationManager(); - assertEquals(-1, underReplicaMgr1.getCheckAllLedgersCTime()); - long curTime = System.currentTimeMillis(); - underReplicaMgr2.setCheckAllLedgersCTime(curTime); - assertEquals(curTime, underReplicaMgr1.getCheckAllLedgersCTime()); - curTime = System.currentTimeMillis(); - underReplicaMgr2.setCheckAllLedgersCTime(curTime); - assertEquals(curTime, underReplicaMgr1.getCheckAllLedgersCTime()); - } - - @Test - public void testPlacementPolicyCheckCTime() throws Exception { - @Cleanup - LedgerUnderreplicationManager underReplicaMgr1 = lmf1.newLedgerUnderreplicationManager(); - @Cleanup - LedgerUnderreplicationManager underReplicaMgr2 = lmf2.newLedgerUnderreplicationManager(); - assertEquals(-1, underReplicaMgr1.getPlacementPolicyCheckCTime()); - long curTime = System.currentTimeMillis(); - underReplicaMgr2.setPlacementPolicyCheckCTime(curTime); - assertEquals(curTime, underReplicaMgr1.getPlacementPolicyCheckCTime()); - curTime = System.currentTimeMillis(); - underReplicaMgr2.setPlacementPolicyCheckCTime(curTime); - assertEquals(curTime, underReplicaMgr1.getPlacementPolicyCheckCTime()); - } - - @Test - public void testReplicasCheckCTime() throws Exception { - @Cleanup - LedgerUnderreplicationManager underReplicaMgr1 = lmf1.newLedgerUnderreplicationManager(); - @Cleanup - LedgerUnderreplicationManager underReplicaMgr2 = lmf2.newLedgerUnderreplicationManager(); - assertEquals(-1, underReplicaMgr1.getReplicasCheckCTime()); - long curTime = System.currentTimeMillis(); - underReplicaMgr2.setReplicasCheckCTime(curTime); - assertEquals(curTime, underReplicaMgr1.getReplicasCheckCTime()); - curTime = System.currentTimeMillis(); - underReplicaMgr2.setReplicasCheckCTime(curTime); - assertEquals(curTime, underReplicaMgr1.getReplicasCheckCTime()); - } - - private void verifyMarkLedgerUnderreplicated(Collection missingReplica) - throws KeeperException, InterruptedException, ReplicationException { - Long ledgerA = 0xfeadeefdacL; - String znodeA = getUrLedgerZnode(ledgerA); - LedgerUnderreplicationManager replicaMgr = lmf1 - .newLedgerUnderreplicationManager(); - for (String replica : missingReplica) { - replicaMgr.markLedgerUnderreplicated(ledgerA, replica); - } - - String urLedgerA = getData(znodeA); - UnderreplicatedLedgerFormat.Builder builderA = UnderreplicatedLedgerFormat - .newBuilder(); - for (String replica : missingReplica) { - builderA.addReplica(replica); - } - List replicaList = builderA.getReplicaList(); - - for (String replica : missingReplica) { - assertTrue("UrLedger:" + urLedgerA - + " doesn't contain failed bookie :" + replica, replicaList - .contains(replica)); - } - } - - private String getData(String znode) { - try { - byte[] data = zkc1.getData(znode, false, null); - return new String(data); - } catch (KeeperException e) { - LOG.error("Exception while reading data from znode :" + znode); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Exception while reading data from znode :" + znode); - } - return ""; - - } - - private String getUrLedgerZnode(long ledgerId) { - return ZkLedgerUnderreplicationManager.getUrLedgerZnode(urLedgerPath, ledgerId); - } - - private void takeLedgerAndRelease(final LedgerUnderreplicationManager m, - final CountDownLatch latch, int numberOfIterations) { - for (int i = 0; i < numberOfIterations; i++) { - try { - long ledgerToRereplicate = m.getLedgerToRereplicate(); - m.releaseUnderreplicatedLedger(ledgerToRereplicate); - } catch (UnavailableException e) { - LOG.error("UnavailableException when " - + "taking or releasing lock", e); - } - latch.countDown(); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestReplicationWorker.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestReplicationWorker.java deleted file mode 100644 index f4a9245c76d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestReplicationWorker.java +++ /dev/null @@ -1,1492 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.replication; - -import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE; -import static org.apache.bookkeeper.replication.ReplicationStats.NUM_ENTRIES_UNABLE_TO_READ_FOR_REPLICATION; -import static org.apache.bookkeeper.replication.ReplicationStats.REPLICATION_SCOPE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.util.HashedWheelTimer; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.URI; -import java.net.UnknownHostException; -import java.util.Enumeration; -import java.util.List; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; -import java.util.TimerTask; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; -import lombok.Cleanup; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.client.ClientUtil; -import org.apache.bookkeeper.client.EnsemblePlacementPolicy; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.RackawareEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.ZoneawareEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.feature.FeatureProvider; -import org.apache.bookkeeper.meta.AbstractZkLedgerManager; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataClientDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.exceptions.MetadataException; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.bookkeeper.proto.BookieAddressResolver; -import org.apache.bookkeeper.replication.ReplicationException.CompatibilityException; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.stats.Gauge; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.util.StaticDNSResolver; -import org.apache.bookkeeper.zookeeper.BoundExponentialBackoffRetryPolicy; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.bookkeeper.zookeeper.ZooKeeperWatcherBase; -import org.apache.commons.lang3.mutable.MutableObject; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.apache.zookeeper.AsyncCallback.StatCallback; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.ZooKeeper.States; -import org.apache.zookeeper.data.Stat; -import org.awaitility.Awaitility; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the ReplicationWroker, where it has to replicate the fragments from - * failed Bookies to given target Bookie. - */ -public class TestReplicationWorker extends BookKeeperClusterTestCase { - - private static final byte[] TESTPASSWD = "testpasswd".getBytes(); - private static final Logger LOG = LoggerFactory - .getLogger(TestReplicationWorker.class); - private String basePath = ""; - private String baseLockPath = ""; - private MetadataBookieDriver driver; - private LedgerManagerFactory mFactory; - private LedgerUnderreplicationManager underReplicationManager; - private LedgerManager ledgerManager; - private static byte[] data = "TestReplicationWorker".getBytes(); - private OrderedScheduler scheduler; - private String zkLedgersRootPath; - - public TestReplicationWorker() { - this("org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"); - } - - TestReplicationWorker(String ledgerManagerFactory) { - super(3, 300); - LOG.info("Running test case using ledger manager : " - + ledgerManagerFactory); - // set ledger manager name - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseConf.setRereplicationEntryBatchSize(3); - baseConf.setZkTimeout(7000); - baseConf.setZkRetryBackoffMaxMs(500); - baseConf.setZkRetryBackoffStartMs(10); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - - zkLedgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(baseClientConf); - basePath = zkLedgersRootPath + '/' - + BookKeeperConstants.UNDER_REPLICATION_NODE - + BookKeeperConstants.DEFAULT_ZK_LEDGERS_ROOT_PATH; - baseLockPath = zkLedgersRootPath + '/' - + BookKeeperConstants.UNDER_REPLICATION_NODE - + "/locks"; - - this.scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduler") - .numThreads(1) - .build(); - - this.driver = MetadataDrivers.getBookieDriver( - URI.create(baseConf.getMetadataServiceUri())); - this.driver.initialize( - baseConf, - NullStatsLogger.INSTANCE); - // initialize urReplicationManager - mFactory = driver.getLedgerManagerFactory(); - ledgerManager = mFactory.newLedgerManager(); - underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - if (null != underReplicationManager){ - underReplicationManager.close(); - underReplicationManager = null; - } - if (null != driver) { - driver.close(); - } - } - - /** - * Tests that replication worker should replicate the failed bookie - * fragments to target bookie given to the worker. - */ - @Test - public void testRWShouldReplicateFragmentsToTargetBookie() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - LOG.info("Killing Bookie : {}", replicaToKill); - killBookie(replicaToKill); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - - ReplicationWorker rw = new ReplicationWorker(baseConf); - - rw.start(); - try { - - underReplicationManager.markLedgerUnderreplicated(lh.getId(), - replicaToKill.toString()); - - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)) { - Thread.sleep(100); - } - - killAllBookies(lh, newBkAddr); - - // Should be able to read the entries from 0-9 - verifyRecoveredLedgers(lh, 0, 9); - } finally { - rw.shutdown(); - } - } - - /** - * Tests that replication worker should retry for replication until enough - * bookies available for replication. - */ - @Test - public void testRWShouldRetryUntilThereAreEnoughBksAvailableForReplication() - throws Exception { - LedgerHandle lh = bkc.createLedger(1, 1, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - lh.close(); - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - LOG.info("Killing Bookie : {}", replicaToKill); - ServerConfiguration killedBookieConfig = killBookie(replicaToKill); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr :" + newBkAddr); - - killAllBookies(lh, newBkAddr); - ReplicationWorker rw = new ReplicationWorker(baseConf); - - rw.start(); - try { - underReplicationManager.markLedgerUnderreplicated(lh.getId(), - replicaToKill.toString()); - int counter = 30; - while (counter-- > 0) { - assertTrue("Expecting that replication should not complete", - ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)); - Thread.sleep(100); - } - // restart killed bookie - startAndAddBookie(killedBookieConfig); - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)) { - Thread.sleep(100); - } - // Should be able to read the entries from 0-9 - verifyRecoveredLedgers(lh, 0, 9); - } finally { - rw.shutdown(); - } - } - - /** - * Tests that replication worker1 should take one fragment replication and - * other replication worker also should compete for the replication. - */ - @Test - public void test2RWsShouldCompeteForReplicationOf2FragmentsAndCompleteReplication() - throws Exception { - LedgerHandle lh = bkc.createLedger(2, 2, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - lh.close(); - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - LOG.info("Killing Bookie : {}", replicaToKill); - ServerConfiguration killedBookieConfig = killBookie(replicaToKill); - - killAllBookies(lh, null); - // Starte RW1 - BookieId newBkAddr1 = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr1); - ReplicationWorker rw1 = new ReplicationWorker(baseConf); - - // Starte RW2 - BookieId newBkAddr2 = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr2); - ReplicationWorker rw2 = new ReplicationWorker(baseConf); - rw1.start(); - rw2.start(); - - try { - underReplicationManager.markLedgerUnderreplicated(lh.getId(), - replicaToKill.toString()); - int counter = 10; - while (counter-- > 0) { - assertTrue("Expecting that replication should not complete", - ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)); - Thread.sleep(100); - } - // restart killed bookie - startAndAddBookie(killedBookieConfig); - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)) { - Thread.sleep(100); - } - // Should be able to read the entries from 0-9 - verifyRecoveredLedgers(lh, 0, 9); - } finally { - rw1.shutdown(); - rw2.shutdown(); - } - } - - /** - * Tests that Replication worker should clean the leadger under replication - * node of the ledger already deleted. - */ - @Test - public void testRWShouldCleanTheLedgerFromUnderReplicationIfLedgerAlreadyDeleted() - throws Exception { - LedgerHandle lh = bkc.createLedger(2, 2, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - lh.close(); - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - LOG.info("Killing Bookie : {}", replicaToKill); - killBookie(replicaToKill); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - ReplicationWorker rw = new ReplicationWorker(baseConf); - rw.start(); - - try { - bkc.deleteLedger(lh.getId()); // Deleting the ledger - // Also mark ledger as in UnderReplication - underReplicationManager.markLedgerUnderreplicated(lh.getId(), - replicaToKill.toString()); - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)) { - Thread.sleep(100); - } - } finally { - rw.shutdown(); - } - - } - - @Test - public void testMultipleLedgerReplicationWithReplicationWorker() - throws Exception { - // Ledger1 - LedgerHandle lh1 = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh1.addEntry(data); - } - BookieId replicaToKillFromFirstLedger = lh1.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - LOG.info("Killing Bookie : {}", replicaToKillFromFirstLedger); - - // Ledger2 - LedgerHandle lh2 = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh2.addEntry(data); - } - BookieId replicaToKillFromSecondLedger = lh2.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - LOG.info("Killing Bookie : {}", replicaToKillFromSecondLedger); - - // Kill ledger1 - killBookie(replicaToKillFromFirstLedger); - lh1.close(); - // Kill ledger2 - killBookie(replicaToKillFromFirstLedger); - lh2.close(); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - - ReplicationWorker rw = new ReplicationWorker(baseConf); - - rw.start(); - try { - - // Mark ledger1 and 2 as underreplicated - underReplicationManager.markLedgerUnderreplicated(lh1.getId(), - replicaToKillFromFirstLedger.toString()); - underReplicationManager.markLedgerUnderreplicated(lh2.getId(), - replicaToKillFromSecondLedger.toString()); - - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh1 - .getId(), basePath)) { - Thread.sleep(100); - } - - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh2 - .getId(), basePath)) { - Thread.sleep(100); - } - - killAllBookies(lh1, newBkAddr); - - // Should be able to read the entries from 0-9 - verifyRecoveredLedgers(lh1, 0, 9); - verifyRecoveredLedgers(lh2, 0, 9); - } finally { - rw.shutdown(); - } - - } - - @Test - public void testMultipleLedgerReplicationWithReplicationWorkerBatchRead() throws Exception { - LedgerHandle lh1 = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, TESTPASSWD); - for (int i = 0; i < 200; ++i) { - lh1.addEntry(data); - } - BookieId replicaToKillFromFirstLedger = lh1.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - LedgerHandle lh2 = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, TESTPASSWD); - for (int i = 0; i < 200; ++i) { - lh2.addEntry(data); - } - - BookieId replicaToKillFromSecondLedger = lh2.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - LOG.info("Killing Bookie : {}", replicaToKillFromFirstLedger); - killBookie(replicaToKillFromFirstLedger); - lh1.close(); - - LOG.info("Killing Bookie : {}", replicaToKillFromSecondLedger); - killBookie(replicaToKillFromSecondLedger); - lh2.close(); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - - if (replicaToKillFromFirstLedger != replicaToKillFromSecondLedger) { - BookieId newBkAddr2 = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr2); - } - - ClientConfiguration clientConfiguration = new ClientConfiguration(baseClientConf); - clientConfiguration.setUseV2WireProtocol(true); - clientConfiguration.setRecoveryBatchReadEnabled(true); - clientConfiguration.setBatchReadEnabled(true); - clientConfiguration.setRereplicationEntryBatchSize(100); - clientConfiguration.setReplicationRateByBytes(3 * 1024); - ReplicationWorker rw = new ReplicationWorker(new ServerConfiguration(clientConfiguration)); - - rw.start(); - try { - // Mark ledger1 and ledger2 as underreplicated - underReplicationManager.markLedgerUnderreplicated(lh1.getId(), replicaToKillFromFirstLedger.toString()); - underReplicationManager.markLedgerUnderreplicated(lh2.getId(), replicaToKillFromSecondLedger.toString()); - - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh1.getId(), basePath)) { - Thread.sleep(100); - } - - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh2.getId(), basePath)) { - Thread.sleep(100); - } - - killAllBookies(lh1, newBkAddr); - - // Should be able to read the entries from 0-99 - verifyRecoveredLedgers(lh1, 0, 199); - verifyRecoveredLedgers(lh2, 0, 199); - } finally { - rw.shutdown(); - } - } - - /** - * Tests that ReplicationWorker should fence the ledger and release ledger - * lock after timeout. Then replication should happen normally. - */ - @Test - public void testRWShouldReplicateTheLedgersAfterTimeoutIfLastFragmentIsUR() - throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - LOG.info("Killing Bookie : {}", replicaToKill); - killBookie(replicaToKill); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - - // set to 3s instead of default 30s - baseConf.setOpenLedgerRereplicationGracePeriod("3000"); - ReplicationWorker rw = new ReplicationWorker(baseConf); - - @Cleanup MetadataClientDriver clientDriver = MetadataDrivers.getClientDriver( - URI.create(baseClientConf.getMetadataServiceUri())); - clientDriver.initialize(baseClientConf, scheduler, NullStatsLogger.INSTANCE, Optional.empty()); - - LedgerManagerFactory mFactory = clientDriver.getLedgerManagerFactory(); - - LedgerUnderreplicationManager underReplicationManager = mFactory - .newLedgerUnderreplicationManager(); - rw.start(); - try { - - underReplicationManager.markLedgerUnderreplicated(lh.getId(), - replicaToKill.toString()); - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)) { - Thread.sleep(100); - } - killAllBookies(lh, newBkAddr); - // Should be able to read the entries from 0-9 - verifyRecoveredLedgers(lh, 0, 9); - lh = bkc.openLedgerNoRecovery(lh.getId(), - BookKeeper.DigestType.CRC32, TESTPASSWD); - assertFalse("Ledger must have been closed by RW", ClientUtil - .isLedgerOpen(lh)); - } finally { - rw.shutdown(); - underReplicationManager.close(); - } - - } - - @Test - public void testBookiesNotAvailableScenarioForReplicationWorker() throws Exception { - int ensembleSize = 3; - LedgerHandle lh = bkc.createLedger(ensembleSize, ensembleSize, BookKeeper.DigestType.CRC32, TESTPASSWD); - - int numOfEntries = 7; - for (int i = 0; i < numOfEntries; i++) { - lh.addEntry(data); - } - lh.close(); - - BookieId[] bookiesKilled = new BookieId[ensembleSize]; - ServerConfiguration[] killedBookiesConfig = new ServerConfiguration[ensembleSize]; - - // kill all bookies - for (int i = 0; i < ensembleSize; i++) { - bookiesKilled[i] = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(i); - killedBookiesConfig[i] = getBkConf(bookiesKilled[i]); - LOG.info("Killing Bookie : {}", bookiesKilled[i]); - killBookie(bookiesKilled[i]); - } - - // start new bookiesToKill number of bookies - for (int i = 0; i < ensembleSize; i++) { - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - } - - // create couple of replicationworkers - ServerConfiguration newRWConf = new ServerConfiguration(baseConf); - newRWConf.setLockReleaseOfFailedLedgerGracePeriod("64"); - ReplicationWorker rw1 = new ReplicationWorker(newRWConf); - ReplicationWorker rw2 = new ReplicationWorker(newRWConf); - - @Cleanup - MetadataClientDriver clientDriver = MetadataDrivers - .getClientDriver(URI.create(baseClientConf.getMetadataServiceUri())); - clientDriver.initialize(baseClientConf, scheduler, NullStatsLogger.INSTANCE, Optional.empty()); - - LedgerManagerFactory mFactory = clientDriver.getLedgerManagerFactory(); - - LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - try { - //mark ledger underreplicated - for (int i = 0; i < bookiesKilled.length; i++) { - underReplicationManager.markLedgerUnderreplicated(lh.getId(), bookiesKilled[i].toString()); - } - while (!ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), basePath)) { - Thread.sleep(100); - } - rw1.start(); - rw2.start(); - - AtomicBoolean isBookieRestarted = new AtomicBoolean(false); - - (new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(3000); - isBookieRestarted.set(true); - /* - * after sleeping for 3000 msecs, restart one of the - * bookie, so that replication can succeed. - */ - startBookie(killedBookiesConfig[0]); - } catch (Exception e) { - e.printStackTrace(); - } - } - })).start(); - - int rw1PrevFailedAttemptsCount = 0; - int rw2PrevFailedAttemptsCount = 0; - while (!isBookieRestarted.get()) { - /* - * since all the bookies containing the ledger entries are down - * replication wouldnt have succeeded. - */ - assertTrue("Ledger: " + lh.getId() + " should be underreplicated", - ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), basePath)); - - // the number of failed attempts should have increased. - int rw1CurFailedAttemptsCount = rw1.replicationFailedLedgers.get(lh.getId()).get(); - assertTrue( - "The current number of failed attempts: " + rw1CurFailedAttemptsCount - + " should be greater than or equal to previous value: " + rw1PrevFailedAttemptsCount, - rw1CurFailedAttemptsCount >= rw1PrevFailedAttemptsCount); - rw1PrevFailedAttemptsCount = rw1CurFailedAttemptsCount; - - int rw2CurFailedAttemptsCount = rw2.replicationFailedLedgers.get(lh.getId()).get(); - assertTrue( - "The current number of failed attempts: " + rw2CurFailedAttemptsCount - + " should be greater than or equal to previous value: " + rw2PrevFailedAttemptsCount, - rw2CurFailedAttemptsCount >= rw2PrevFailedAttemptsCount); - rw2PrevFailedAttemptsCount = rw2CurFailedAttemptsCount; - - Thread.sleep(50); - } - - /** - * since one of the killed bookie is restarted, replicationworker - * should succeed in replicating this under replicated ledger and it - * shouldn't be under replicated anymore. - */ - int timeToWaitForReplicationToComplete = 20000; - int timeWaited = 0; - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), basePath)) { - Thread.sleep(100); - timeWaited += 100; - if (timeWaited == timeToWaitForReplicationToComplete) { - fail("Ledger should be replicated by now"); - } - } - - rw1PrevFailedAttemptsCount = rw1.replicationFailedLedgers.get(lh.getId()).get(); - rw2PrevFailedAttemptsCount = rw2.replicationFailedLedgers.get(lh.getId()).get(); - Thread.sleep(2000); - // now since the ledger is replicated, number of failed attempts - // counter shouldn't be increased even after sleeping for sometime. - assertEquals("rw1 failedattempts", rw1PrevFailedAttemptsCount, - rw1.replicationFailedLedgers.get(lh.getId()).get()); - assertEquals("rw2 failed attempts ", rw2PrevFailedAttemptsCount, - rw2.replicationFailedLedgers.get(lh.getId()).get()); - - /* - * Since these entries are eventually available, and replication has - * eventually succeeded, in one of the RW - * unableToReadEntriesForReplication should be 0. - */ - int rw1UnableToReadEntriesForReplication = rw1.unableToReadEntriesForReplication.get(lh.getId()).size(); - int rw2UnableToReadEntriesForReplication = rw2.unableToReadEntriesForReplication.get(lh.getId()).size(); - assertTrue( - "unableToReadEntriesForReplication in RW1: " + rw1UnableToReadEntriesForReplication - + " in RW2: " - + rw2UnableToReadEntriesForReplication, - (rw1UnableToReadEntriesForReplication == 0) - || (rw2UnableToReadEntriesForReplication == 0)); - } finally { - rw1.shutdown(); - rw2.shutdown(); - underReplicationManager.close(); - } - } - - class InjectedReplicationWorker extends ReplicationWorker { - CopyOnWriteArrayList delayReplicationPeriods; - - public InjectedReplicationWorker(ServerConfiguration conf, StatsLogger statsLogger, - CopyOnWriteArrayList delayReplicationPeriods) - throws CompatibilityException, ReplicationException.UnavailableException, - InterruptedException, IOException { - super(conf, statsLogger); - this.delayReplicationPeriods = delayReplicationPeriods; - } - - @Override - void scheduleTaskWithDelay(TimerTask timerTask, long delayPeriod) { - delayReplicationPeriods.add(delayPeriod); - super.scheduleTaskWithDelay(timerTask, delayPeriod); - } - } - - @Test - public void testDeferLedgerLockReleaseForReplicationWorker() throws Exception { - int ensembleSize = 3; - LedgerHandle lh = bkc.createLedger(ensembleSize, ensembleSize, BookKeeper.DigestType.CRC32, TESTPASSWD); - int numOfEntries = 7; - for (int i = 0; i < numOfEntries; i++) { - lh.addEntry(data); - } - lh.close(); - - BookieId[] bookiesKilled = new BookieId[ensembleSize]; - ServerConfiguration[] killedBookiesConfig = new ServerConfiguration[ensembleSize]; - - // kill all bookies - for (int i = 0; i < ensembleSize; i++) { - bookiesKilled[i] = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(i); - killedBookiesConfig[i] = getBkConf(bookiesKilled[i]); - LOG.info("Killing Bookie : {}", bookiesKilled[i]); - killBookie(bookiesKilled[i]); - } - - // start new bookiesToKill number of bookies - for (int i = 0; i < ensembleSize; i++) { - startNewBookieAndReturnBookieId(); - } - - // create couple of replicationworkers - long lockReleaseOfFailedLedgerGracePeriod = 64L; - long baseBackoffForLockReleaseOfFailedLedger = lockReleaseOfFailedLedgerGracePeriod - / (int) Math.pow(2, ReplicationWorker.NUM_OF_EXPONENTIAL_BACKOFF_RETRIALS); - ServerConfiguration newRWConf = new ServerConfiguration(baseConf); - newRWConf.setLockReleaseOfFailedLedgerGracePeriod(Long.toString(lockReleaseOfFailedLedgerGracePeriod)); - newRWConf.setRereplicationEntryBatchSize(1000); - CopyOnWriteArrayList rw1DelayReplicationPeriods = new CopyOnWriteArrayList(); - CopyOnWriteArrayList rw2DelayReplicationPeriods = new CopyOnWriteArrayList(); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger1 = statsProvider.getStatsLogger("rw1"); - TestStatsLogger statsLogger2 = statsProvider.getStatsLogger("rw2"); - ReplicationWorker rw1 = new InjectedReplicationWorker(newRWConf, statsLogger1, rw1DelayReplicationPeriods); - ReplicationWorker rw2 = new InjectedReplicationWorker(newRWConf, statsLogger2, rw2DelayReplicationPeriods); - - Counter numEntriesUnableToReadForReplication1 = statsLogger1 - .getCounter(NUM_ENTRIES_UNABLE_TO_READ_FOR_REPLICATION); - Counter numEntriesUnableToReadForReplication2 = statsLogger2 - .getCounter(NUM_ENTRIES_UNABLE_TO_READ_FOR_REPLICATION); - @Cleanup - MetadataClientDriver clientDriver = MetadataDrivers - .getClientDriver(URI.create(baseClientConf.getMetadataServiceUri())); - clientDriver.initialize(baseClientConf, scheduler, NullStatsLogger.INSTANCE, Optional.empty()); - - LedgerManagerFactory mFactory = clientDriver.getLedgerManagerFactory(); - - LedgerUnderreplicationManager underReplicationManager = mFactory.newLedgerUnderreplicationManager(); - try { - // mark ledger underreplicated - for (int i = 0; i < bookiesKilled.length; i++) { - underReplicationManager.markLedgerUnderreplicated(lh.getId(), bookiesKilled[i].toString()); - } - while (!ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), basePath)) { - Thread.sleep(100); - } - rw1.start(); - rw2.start(); - - // wait for RWs to complete 'numOfAttemptsToWaitFor' failed attempts - int numOfAttemptsToWaitFor = 10; - while ((rw1.replicationFailedLedgers.get(lh.getId()).get() < numOfAttemptsToWaitFor) - || rw2.replicationFailedLedgers.get(lh.getId()).get() < numOfAttemptsToWaitFor) { - Thread.sleep(500); - } - - /* - * since all the bookies containing the ledger entries are down - * replication wouldn't have succeeded. - */ - assertTrue("Ledger: " + lh.getId() + " should be underreplicated", - ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), basePath)); - - /* - * since RW failed 'numOfAttemptsToWaitFor' number of times, we - * should have atleast (numOfAttemptsToWaitFor - 1) - * delayReplicationPeriods and their value should be - * (lockReleaseOfFailedLedgerGracePeriod/16) , 2 * previous value,.. - * with max : lockReleaseOfFailedLedgerGracePeriod - */ - for (int i = 0; i < ((numOfAttemptsToWaitFor - 1)); i++) { - long expectedDelayValue = Math.min(lockReleaseOfFailedLedgerGracePeriod, - baseBackoffForLockReleaseOfFailedLedger * (1 << i)); - assertEquals("RW1 delayperiod", (Long) expectedDelayValue, rw1DelayReplicationPeriods.get(i)); - assertEquals("RW2 delayperiod", (Long) expectedDelayValue, rw2DelayReplicationPeriods.get(i)); - } - - /* - * RW wont try to replicate until and unless RW succeed in reading - * those failed entries before proceeding with replication of under - * replicated fragment, so the numEntriesUnableToReadForReplication - * should be just 'numOfEntries', though RW failed to replicate - * multiple times. - */ - assertEquals("numEntriesUnableToReadForReplication for RW1", Long.valueOf((long) numOfEntries), - numEntriesUnableToReadForReplication1.get()); - assertEquals("numEntriesUnableToReadForReplication for RW2", Long.valueOf((long) numOfEntries), - numEntriesUnableToReadForReplication2.get()); - - /* - * Since these entries are unavailable, - * unableToReadEntriesForReplication should be of size numOfEntries. - */ - assertEquals("RW1 unabletoreadentries", numOfEntries, - rw1.unableToReadEntriesForReplication.get(lh.getId()).size()); - assertEquals("RW2 unabletoreadentries", numOfEntries, - rw2.unableToReadEntriesForReplication.get(lh.getId()).size()); - } finally { - rw1.shutdown(); - rw2.shutdown(); - underReplicationManager.close(); - } - } - - /** - * Tests that ReplicationWorker should not have identified for postponing - * the replication if ledger is in open state and lastFragment is not in - * underReplication state. Note that RW should not fence such ledgers. - */ - @Test - public void testRWShouldReplicateTheLedgersAfterTimeoutIfLastFragmentIsNotUR() - throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, - TESTPASSWD); - - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - - LOG.info("Killing Bookie : {}", replicaToKill); - killBookie(replicaToKill); - - BookieId newBkAddr = startNewBookieAndReturnBookieId(); - LOG.info("New Bookie addr : {}", newBkAddr); - - // Reform ensemble...Making sure that last fragment is not in - // under-replication - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - - ReplicationWorker rw = new ReplicationWorker(baseConf); - - baseClientConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - - @Cleanup MetadataClientDriver driver = MetadataDrivers.getClientDriver( - URI.create(baseClientConf.getMetadataServiceUri())); - driver.initialize(baseClientConf, scheduler, NullStatsLogger.INSTANCE, Optional.empty()); - - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - - LedgerUnderreplicationManager underReplicationManager = mFactory - .newLedgerUnderreplicationManager(); - - rw.start(); - try { - - underReplicationManager.markLedgerUnderreplicated(lh.getId(), - replicaToKill.toString()); - while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh - .getId(), basePath)) { - Thread.sleep(100); - } - - killAllBookies(lh, newBkAddr); - - // Should be able to read the entries from 0-9 - verifyRecoveredLedgers(lh, 0, 9); - lh = bkc.openLedgerNoRecovery(lh.getId(), - BookKeeper.DigestType.CRC32, TESTPASSWD); - - // Ledger should be still in open state - assertTrue("Ledger must have been closed by RW", ClientUtil - .isLedgerOpen(lh)); - } finally { - rw.shutdown(); - underReplicationManager.close(); - } - - } - - /** - * Test that the replication worker will not shutdown on a simple ZK disconnection. - */ - @Test - public void testRWZKConnectionLost() throws Exception { - try (ZooKeeperClient zk = ZooKeeperClient.newBuilder() - .connectString(zkUtil.getZooKeeperConnectString()) - .sessionTimeoutMs(10000) - .build()) { - - ReplicationWorker rw = new ReplicationWorker(baseConf); - rw.start(); - for (int i = 0; i < 10; i++) { - if (rw.isRunning()) { - break; - } - Thread.sleep(1000); - } - assertTrue("Replication worker should be running", rw.isRunning()); - - stopZKCluster(); - // ZK is down for shorter period than reconnect timeout - Thread.sleep(1000); - startZKCluster(); - - assertTrue("Replication worker should not shutdown", rw.isRunning()); - } - } - - /** - * Test that the replication worker shuts down on non-recoverable ZK connection loss. - */ - @Test - public void testRWZKConnectionLostOnNonRecoverableZkError() throws Exception { - for (int j = 0; j < 3; j++) { - LedgerHandle lh = bkc.createLedger(1, 1, 1, - BookKeeper.DigestType.CRC32, TESTPASSWD, - null); - final long createdLedgerId = lh.getId(); - for (int i = 0; i < 10; i++) { - lh.addEntry(data); - } - lh.close(); - } - - killBookie(2); - killBookie(1); - startNewBookie(); - startNewBookie(); - - servers.get(0).getConfiguration().setRwRereplicateBackoffMs(100); - servers.get(0).startAutoRecovery(); - - Auditor auditor = getAuditor(10, TimeUnit.SECONDS); - ReplicationWorker rw = servers.get(0).getReplicationWorker(); - - ZkLedgerUnderreplicationManager ledgerUnderreplicationManager = - (ZkLedgerUnderreplicationManager) FieldUtils.readField(auditor, - "ledgerUnderreplicationManager", true); - - ZooKeeper zkc = (ZooKeeper) FieldUtils.readField(ledgerUnderreplicationManager, "zkc", true); - auditor.submitAuditTask().get(); - - assertTrue(zkc.getState().isConnected()); - zkc.close(); - assertFalse(zkc.getState().isConnected()); - - auditor.submitAuditTask(); - rw.run(); - - for (int i = 0; i < 10; i++) { - if (!rw.isRunning() && !auditor.isRunning()) { - break; - } - Thread.sleep(1000); - } - assertFalse("Replication worker should NOT be running", rw.isRunning()); - assertFalse("Auditor should NOT be running", auditor.isRunning()); - } - - private void killAllBookies(LedgerHandle lh, BookieId excludeBK) - throws Exception { - // Killing all bookies except newly replicated bookie - for (Entry> entry : - lh.getLedgerMetadata().getAllEnsembles().entrySet()) { - List bookies = entry.getValue(); - for (BookieId bookie : bookies) { - if (bookie.equals(excludeBK)) { - continue; - } - killBookie(bookie); - } - } - } - - private void verifyRecoveredLedgers(LedgerHandle lh, long startEntryId, - long endEntryId) throws BKException, InterruptedException { - LedgerHandle lhs = bkc.openLedgerNoRecovery(lh.getId(), - BookKeeper.DigestType.CRC32, TESTPASSWD); - Enumeration entries = lhs.readEntries(startEntryId, - endEntryId); - assertTrue("Should have the elements", entries.hasMoreElements()); - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertEquals("TestReplicationWorker", new String(entry.getEntry())); - } - } - - class MockZooKeeperClient extends ZooKeeperClient { - private final String connectString; - private final int sessionTimeoutMs; - private final ZooKeeperWatcherBase watcherManager; - private volatile String pathOfSetDataToFail; - private volatile String pathOfDeleteToFail; - private AtomicInteger numOfTimesSetDataFailed = new AtomicInteger(); - private AtomicInteger numOfTimesDeleteFailed = new AtomicInteger(); - - MockZooKeeperClient(String connectString, int sessionTimeoutMs, ZooKeeperWatcherBase watcher) - throws IOException { - /* - * in OperationalRetryPolicy maxRetries is set to 0. So it wont - * retry incase of any error/exception. - */ - super(connectString, sessionTimeoutMs, watcher, - new BoundExponentialBackoffRetryPolicy(sessionTimeoutMs, sessionTimeoutMs, Integer.MAX_VALUE), - new BoundExponentialBackoffRetryPolicy(sessionTimeoutMs, sessionTimeoutMs, 0), - NullStatsLogger.INSTANCE, 1, 0, false); - this.connectString = connectString; - this.sessionTimeoutMs = sessionTimeoutMs; - this.watcherManager = watcher; - } - - @Override - protected ZooKeeper createZooKeeper() throws IOException { - return new MockZooKeeper(this.connectString, this.sessionTimeoutMs, this.watcherManager, false); - } - - private void setPathOfSetDataToFail(String pathOfSetDataToFail) { - this.pathOfSetDataToFail = pathOfSetDataToFail; - } - - private void setPathOfDeleteToFail(String pathOfDeleteToFail) { - this.pathOfDeleteToFail = pathOfDeleteToFail; - } - - private int getNumOfTimesSetDataFailed() { - return numOfTimesSetDataFailed.get(); - } - - private int getNumOfTimesDeleteFailed() { - return numOfTimesDeleteFailed.get(); - } - - class MockZooKeeper extends ZooKeeper { - public MockZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) - throws IOException { - super(connectString, sessionTimeout, watcher, canBeReadOnly); - } - - @Override - public void setData(final String path, final byte[] data, final int version, final StatCallback cb, - final Object context) { - if ((pathOfSetDataToFail != null) && (pathOfSetDataToFail.equals(path))) { - /* - * if pathOfSetDataToFail matches with the path of the node, - * then callback with CONNECTIONLOSS error. - */ - LOG.error("setData of MockZooKeeper, is failing with CONNECTIONLOSS for path: {}", path); - numOfTimesSetDataFailed.incrementAndGet(); - cb.processResult(KeeperException.Code.CONNECTIONLOSS.intValue(), path, context, null); - } else { - super.setData(path, data, version, cb, context); - } - } - - @Override - public void delete(final String path, final int version) throws KeeperException, InterruptedException { - if ((pathOfDeleteToFail != null) && (pathOfDeleteToFail.equals(path))) { - /* - * if pathOfDeleteToFail matches with the path of the node, - * then throw CONNECTIONLOSS exception. - */ - LOG.error("delete of MockZooKeeper, is failing with CONNECTIONLOSS for path: {}", path); - numOfTimesDeleteFailed.incrementAndGet(); - throw new KeeperException.ConnectionLossException(); - } else { - super.delete(path, version); - } - } - } - } - - @Test - public void testRWShutDownInTheCaseOfZKOperationFailures() throws Exception { - /* - * create MockZooKeeperClient instance and wait for it to be connected. - */ - int zkSessionTimeOut = 10000; - ZooKeeperWatcherBase zooKeeperWatcherBase = new ZooKeeperWatcherBase(zkSessionTimeOut, - NullStatsLogger.INSTANCE); - MockZooKeeperClient zkFaultInjectionWrapper = new MockZooKeeperClient(zkUtil.getZooKeeperConnectString(), - zkSessionTimeOut, zooKeeperWatcherBase); - zkFaultInjectionWrapper.waitForConnection(); - assertEquals("zkFaultInjectionWrapper should be in connected state", States.CONNECTED, - zkFaultInjectionWrapper.getState()); - long oldZkInstanceSessionId = zkFaultInjectionWrapper.getSessionId(); - - /* - * create ledger and add entries. - */ - BookKeeper bkWithMockZK = new BookKeeper(baseClientConf, zkFaultInjectionWrapper); - long ledgerId = 567L; - LedgerHandle lh = bkWithMockZK.createLedgerAdv(ledgerId, 2, 2, 2, - BookKeeper.DigestType.CRC32, TESTPASSWD, - null); - for (int i = 0; i < 10; i++) { - lh.addEntry(i, data); - } - lh.close(); - - /* - * trigger Expired event so that MockZooKeeperClient would run - * 'clientCreator' and create new zk handle. In this case it would - * create MockZooKeeper instance. - */ - zooKeeperWatcherBase.process(new WatchedEvent(EventType.None, KeeperState.Expired, "")); - zkFaultInjectionWrapper.waitForConnection(); - for (int i = 0; i < 10; i++) { - if (zkFaultInjectionWrapper.getState() == States.CONNECTED) { - break; - } - Thread.sleep(200); - } - assertEquals("zkFaultInjectionWrapper should be in connected state", States.CONNECTED, - zkFaultInjectionWrapper.getState()); - assertNotEquals("Session Id of old and new ZK instance should be different", oldZkInstanceSessionId, - zkFaultInjectionWrapper.getSessionId()); - - /* - * Kill a Bookie, so that ledger becomes underreplicated. Since totally - * 3 bookies are available and the ensemblesize of the current ledger is - * 2, we should be able to replicate to the other bookie. - */ - BookieId replicaToKill = lh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - LOG.info("Killing Bookie id {}", replicaToKill); - killBookie(replicaToKill); - - /* - * Start RW. - */ - ReplicationWorker rw = new ReplicationWorker(baseConf, bkWithMockZK, false, NullStatsLogger.INSTANCE); - rw.start(); - try { - for (int i = 0; i < 40; i++) { - if (rw.isRunning()) { - break; - } - LOG.info("Waiting for the RW to start..."); - Thread.sleep(500); - } - assertTrue("RW should be running", rw.isRunning()); - - /* - * Since Auditor is not running, ledger needs to be marked - * underreplicated explicitly. But before marking ledger - * underreplicated, set paths for which MockZooKeeper's setData and - * Delete operation to fail. - * - * ZK.setData will be called by 'updateEnsembleInfo' operation after - * completion of copying to a new bookie. ZK.delete will be called by - * RW.logBKExceptionAndReleaseLedger and finally block in - * 'rereplicate(long ledgerIdToReplicate)' - */ - AbstractZkLedgerManager absZKLedgerManager = (AbstractZkLedgerManager) ledgerManager; - String ledgerPath = absZKLedgerManager.getLedgerPath(ledgerId); - String urLockPath = ZkLedgerUnderreplicationManager - .getUrLedgerLockZnode(ZkLedgerUnderreplicationManager.getUrLockPath(zkLedgersRootPath), ledgerId); - zkFaultInjectionWrapper.setPathOfSetDataToFail(ledgerPath); - zkFaultInjectionWrapper.setPathOfDeleteToFail(urLockPath); - underReplicationManager.markLedgerUnderreplicated(lh.getId(), replicaToKill.toString()); - - /* - * Since there is only one RW, it will try to replicate underreplicated - * ledger. After completion of copying it to a new bookie, it will try - * to update ensembleinfo. Which would fail with our MockZK. After that - * it would try to delete lock znode as part of - * RW.logBKExceptionAndReleaseLedger, which will also fail because of - * our MockZK. In the finally block in 'rereplicate(long - * ledgerIdToReplicate)' it would try one more time to delete the ledger - * and once again it will fail because of our MockZK. So RW gives up and - * shutdowns itself. - */ - for (int i = 0; i < 40; i++) { - if (!rw.isRunning()) { - break; - } - LOG.info("Waiting for the RW to shutdown..."); - Thread.sleep(500); - } - - /* - * as described earlier, numOfTimes setDataFailed should be 1 and - * numOfTimes deleteFailed should be 2 - */ - assertEquals("NumOfTimesSetDataFailed", 1, - zkFaultInjectionWrapper.getNumOfTimesSetDataFailed()); - assertEquals("NumOfTimesDeleteFailed", 2, - zkFaultInjectionWrapper.getNumOfTimesDeleteFailed()); - assertFalse("RW should be shutdown", rw.isRunning()); - } finally { - rw.shutdown(); - zkFaultInjectionWrapper.close(); - bkWithMockZK.close(); - } - } - - @Test - public void testReplicateEmptyOpenStateLedger() throws Exception { - LedgerHandle lh = bkc.createLedger(3, 3, 2, BookKeeper.DigestType.CRC32, TESTPASSWD); - assertFalse(lh.getLedgerMetadata().isClosed()); - - List firstEnsemble = lh.getLedgerMetadata().getAllEnsembles().firstEntry().getValue(); - List ensemble = lh.getLedgerMetadata().getAllEnsembles().entrySet().iterator().next().getValue(); - killBookie(ensemble.get(1)); - - startNewBookie(); - baseConf.setOpenLedgerRereplicationGracePeriod(String.valueOf(30)); - ReplicationWorker replicationWorker = new ReplicationWorker(baseConf); - replicationWorker.start(); - - try { - underReplicationManager.markLedgerUnderreplicated(lh.getId(), ensemble.get(1).toString()); - Awaitility.waitAtMost(60, TimeUnit.SECONDS).untilAsserted(() -> - assertFalse(ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), basePath)) - ); - - LedgerHandle lh1 = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, TESTPASSWD); - assertTrue(lh1.getLedgerMetadata().isClosed()); - } finally { - replicationWorker.shutdown(); - } - } - - @Test - public void testRepairedNotAdheringPlacementPolicyLedgerFragmentsOnRack() throws Exception { - testRepairedNotAdheringPlacementPolicyLedgerFragments(RackawareEnsemblePlacementPolicy.class, null); - } - - @Test - public void testReplicationStats() throws Exception { - BiConsumer checkReplicationStats = (first, rw) -> { - try { - final Method rereplicate = rw.getClass().getDeclaredMethod("rereplicate"); - rereplicate.setAccessible(true); - final Object result = rereplicate.invoke(rw); - final Field statsLoggerField = rw.getClass().getDeclaredField("statsLogger"); - statsLoggerField.setAccessible(true); - final TestStatsLogger statsLogger = (TestStatsLogger) statsLoggerField.get(rw); - - final Counter numDeferLedgerLockReleaseOfFailedLedgerCounter = - statsLogger.getCounter(ReplicationStats.NUM_DEFER_LEDGER_LOCK_RELEASE_OF_FAILED_LEDGER); - final Counter numLedgersReplicatedCounter = - statsLogger.getCounter(ReplicationStats.NUM_FULL_OR_PARTIAL_LEDGERS_REPLICATED); - final Counter numNotAdheringPlacementLedgersCounter = statsLogger - .getCounter(ReplicationStats.NUM_NOT_ADHERING_PLACEMENT_LEDGERS_REPLICATED); - - assertEquals("NUM_DEFER_LEDGER_LOCK_RELEASE_OF_FAILED_LEDGER", - 1, numDeferLedgerLockReleaseOfFailedLedgerCounter.get().longValue()); - - if (first) { - assertFalse((boolean) result); - assertEquals("NUM_FULL_OR_PARTIAL_LEDGERS_REPLICATED", - 0, numLedgersReplicatedCounter.get().longValue()); - assertEquals("NUM_NOT_ADHERING_PLACEMENT_LEDGERS_REPLICATED", - 0, numNotAdheringPlacementLedgersCounter.get().longValue()); - - } else { - assertTrue((boolean) result); - assertEquals("NUM_FULL_OR_PARTIAL_LEDGERS_REPLICATED", - 1, numLedgersReplicatedCounter.get().longValue()); - assertEquals("NUM_NOT_ADHERING_PLACEMENT_LEDGERS_REPLICATED", - 1, numNotAdheringPlacementLedgersCounter.get().longValue()); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - }; - testRepairedNotAdheringPlacementPolicyLedgerFragments( - RackawareEnsemblePlacementPolicy.class, checkReplicationStats); - } - - private void testRepairedNotAdheringPlacementPolicyLedgerFragments( - Class placementPolicyClass, - BiConsumer checkReplicationStats) throws Exception { - List firstThreeBookies = servers.stream().map(ele -> { - try { - return ele.getServer().getBookieId(); - } catch (UnknownHostException e) { - return null; - } - }).filter(Objects::nonNull).collect(Collectors.toList()); - - baseClientConf.setProperty("reppDnsResolverClass", StaticDNSResolver.class.getName()); - baseClientConf.setProperty("enforceStrictZoneawarePlacement", false); - bkc.close(); - bkc = new BookKeeperTestClient(baseClientConf) { - @Override - protected EnsemblePlacementPolicy initializeEnsemblePlacementPolicy(ClientConfiguration conf, - DNSToSwitchMapping dnsResolver, HashedWheelTimer timer, FeatureProvider featureProvider, - StatsLogger statsLogger, BookieAddressResolver bookieAddressResolver) throws IOException { - EnsemblePlacementPolicy ensemblePlacementPolicy = null; - if (ZoneawareEnsemblePlacementPolicy.class == placementPolicyClass) { - ensemblePlacementPolicy = buildZoneAwareEnsemblePlacementPolicy(firstThreeBookies); - } else if (RackawareEnsemblePlacementPolicy.class == placementPolicyClass) { - ensemblePlacementPolicy = buildRackAwareEnsemblePlacementPolicy(firstThreeBookies); - } - ensemblePlacementPolicy.initialize(conf, Optional.ofNullable(dnsResolver), timer, - featureProvider, statsLogger, bookieAddressResolver); - return ensemblePlacementPolicy; - } - }; - - //This ledger not adhering placement policy, the combine(0,1,2) rack is 1. - LedgerHandle lh = bkc.createLedger(3, 3, 3, BookKeeper.DigestType.CRC32, TESTPASSWD); - - int entrySize = 10; - for (int i = 0; i < entrySize; i++) { - lh.addEntry(data); - } - lh.close(); - - int minNumRacksPerWriteQuorumConfValue = 2; - - ServerConfiguration servConf = new ServerConfiguration(confByIndex(0)); - servConf.setMinNumRacksPerWriteQuorum(minNumRacksPerWriteQuorumConfValue); - servConf.setProperty("reppDnsResolverClass", StaticDNSResolver.class.getName()); - servConf.setAuditorPeriodicPlacementPolicyCheckInterval(1000); - servConf.setRepairedPlacementPolicyNotAdheringBookieEnable(true); - - MutableObject auditorRef = new MutableObject(); - try { - TestStatsLogger statsLogger = startAuditorAndWaitForPlacementPolicyCheck(servConf, auditorRef); - Gauge ledgersNotAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_NOT_ADHERING_TO_PLACEMENT_POLICY guage value", - 1, ledgersNotAdheringToPlacementPolicyGuage.getSample()); - Gauge ledgersSoftlyAdheringToPlacementPolicyGuage = statsLogger - .getGauge(ReplicationStats.NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY); - assertEquals("NUM_LEDGERS_SOFTLY_ADHERING_TO_PLACEMENT_POLICY guage value", - 0, ledgersSoftlyAdheringToPlacementPolicyGuage.getSample()); - } finally { - Auditor auditor = auditorRef.getValue(); - if (auditor != null) { - auditor.close(); - } - } - - Stat stat = bkc.getZkHandle() - .exists("/ledgers/underreplication/ledgers/0000/0000/0000/0000/urL0000000000", false); - assertNotNull(stat); - - baseConf.setRepairedPlacementPolicyNotAdheringBookieEnable(true); - BookKeeper bookKeeper = new BookKeeperTestClient(baseClientConf) { - @Override - protected EnsemblePlacementPolicy initializeEnsemblePlacementPolicy(ClientConfiguration conf, - DNSToSwitchMapping dnsResolver, HashedWheelTimer timer, FeatureProvider featureProvider, - StatsLogger statsLogger, BookieAddressResolver bookieAddressResolver) throws IOException { - EnsemblePlacementPolicy ensemblePlacementPolicy = null; - if (ZoneawareEnsemblePlacementPolicy.class == placementPolicyClass) { - ensemblePlacementPolicy = buildZoneAwareEnsemblePlacementPolicy(firstThreeBookies); - } else if (RackawareEnsemblePlacementPolicy.class == placementPolicyClass) { - ensemblePlacementPolicy = buildRackAwareEnsemblePlacementPolicy(firstThreeBookies); - } - ensemblePlacementPolicy.initialize(conf, Optional.ofNullable(dnsResolver), timer, - featureProvider, statsLogger, bookieAddressResolver); - return ensemblePlacementPolicy; - } - }; - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(REPLICATION_SCOPE); - ReplicationWorker rw = new ReplicationWorker(baseConf, bookKeeper, false, statsLogger); - - if (checkReplicationStats != null) { - checkReplicationStats.accept(true, rw); - } else { - rw.start(); - } - - //start new bookie, the rack is /rack2 - BookieId newBookieId = startNewBookieAndReturnBookieId(); - - if (checkReplicationStats != null) { - checkReplicationStats.accept(false, rw); - } - - Awaitility.await().untilAsserted(() -> { - LedgerMetadata metadata = bkc.getLedgerManager().readLedgerMetadata(lh.getId()).get().getValue(); - List newBookies = metadata.getAllEnsembles().get(0L); - assertTrue(newBookies.contains(newBookieId)); - }); - - Awaitility.await().untilAsserted(() -> { - Stat stat1 = bkc.getZkHandle() - .exists("/ledgers/underreplication/ledgers/0000/0000/0000/0000/urL0000000000", false); - assertNull(stat1); - }); - - for (BookieId rack1Book : firstThreeBookies) { - killBookie(rack1Book); - } - - verifyRecoveredLedgers(lh, 0, entrySize - 1); - - if (checkReplicationStats == null) { - rw.shutdown(); - } - baseConf.setRepairedPlacementPolicyNotAdheringBookieEnable(false); - bookKeeper.close(); - } - - private EnsemblePlacementPolicy buildRackAwareEnsemblePlacementPolicy(List bookieIds) { - return new RackawareEnsemblePlacementPolicy() { - @Override - public String resolveNetworkLocation(BookieId addr) { - if (bookieIds.contains(addr)) { - return "/rack1"; - } - //The other bookie is /rack2 - return "/rack2"; - } - }; - } - - private EnsemblePlacementPolicy buildZoneAwareEnsemblePlacementPolicy(List firstThreeBookies) { - return new ZoneawareEnsemblePlacementPolicy() { - @Override - protected String resolveNetworkLocation(BookieId addr) { - //The first three bookie 1 is /zone1/ud1 - //The first three bookie 2,3 is /zone1/ud2 - if (firstThreeBookies.get(0).equals(addr)) { - return "/zone1/ud1"; - } else if (firstThreeBookies.contains(addr)) { - return "/zone1/ud2"; - } - //The other bookie is /zone2/ud1 - return "/zone2/ud1"; - } - }; - } - - private TestStatsLogger startAuditorAndWaitForPlacementPolicyCheck(ServerConfiguration servConf, - MutableObject auditorRef) throws MetadataException, CompatibilityException, KeeperException, - InterruptedException, ReplicationException.UnavailableException, UnknownHostException { - LedgerManagerFactory mFactory = driver.getLedgerManagerFactory(); - LedgerUnderreplicationManager urm = mFactory.newLedgerUnderreplicationManager(); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(AUDITOR_SCOPE); - TestStatsProvider.TestOpStatsLogger placementPolicyCheckStatsLogger = - (TestStatsProvider.TestOpStatsLogger) statsLogger - .getOpStatsLogger(ReplicationStats.PLACEMENT_POLICY_CHECK_TIME); - - final AuditorPeriodicCheckTest.TestAuditor auditor = new AuditorPeriodicCheckTest.TestAuditor( - BookieImpl.getBookieId(servConf).toString(), servConf, bkc, false, statsLogger, null); - auditorRef.setValue(auditor); - CountDownLatch latch = auditor.getLatch(); - assertEquals("PLACEMENT_POLICY_CHECK_TIME SuccessCount", 0, - placementPolicyCheckStatsLogger.getSuccessCount()); - urm.setPlacementPolicyCheckCTime(-1); - auditor.start(); - /* - * since placementPolicyCheckCTime is set to -1, placementPolicyCheck should be - * scheduled to run with no initialdelay - */ - assertTrue("placementPolicyCheck should have executed", latch.await(20, TimeUnit.SECONDS)); - for (int i = 0; i < 20; i++) { - Thread.sleep(100); - if (placementPolicyCheckStatsLogger.getSuccessCount() >= 1) { - break; - } - } - assertEquals("PLACEMENT_POLICY_CHECK_TIME SuccessCount", 1, - placementPolicyCheckStatsLogger.getSuccessCount()); - return statsLogger; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/GSSAPIBookKeeperTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/GSSAPIBookKeeperTest.java deleted file mode 100644 index 55485486f68..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/GSSAPIBookKeeperTest.java +++ /dev/null @@ -1,265 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF 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. -* -*/ -package org.apache.bookkeeper.sasl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicLong; -import javax.security.auth.login.Configuration; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.BKUnauthorizedAccessException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.zookeeper.KeeperException; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * GSSAPI tests. - */ -public class GSSAPIBookKeeperTest extends BookKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(GSSAPIBookKeeperTest.class); - - private static final byte[] PASSWD = "testPasswd".getBytes(); - private static final byte[] ENTRY = "TestEntry".getBytes(); - - private static MiniKdc kdc; - private static Properties conf; - - private static final String non_default_sasl_service_name = "non_default_servicename"; - - @ClassRule - public static TemporaryFolder kdcDir = new TemporaryFolder(); - - @ClassRule - public static TemporaryFolder kerberosWorkDir = new TemporaryFolder(); - - @BeforeClass - public static void startMiniKdc() throws Exception { - - conf = MiniKdc.createConf(); - kdc = new MiniKdc(conf, kdcDir.getRoot()); - kdc.start(); - - // this is just to calculate "localhostName" the same way the bookie does - ServerConfiguration bookieConf = TestBKConfiguration.newServerConfiguration(); - bookieConf.setUseHostNameAsBookieID(true); - String localhostName = BookieImpl.getBookieAddress(bookieConf).getHostName(); - - String principalServerNoRealm = non_default_sasl_service_name + "/" + localhostName; - String principalServer = non_default_sasl_service_name + "/" + localhostName + "@" + kdc.getRealm(); - LOG.info("principalServer: " + principalServer); - String principalClientNoRealm = "bookkeeperclient/" + localhostName; - String principalClient = principalClientNoRealm + "@" + kdc.getRealm(); - LOG.info("principalClient: " + principalClient); - - File keytabClient = new File(kerberosWorkDir.getRoot(), "bookkeeperclient.keytab"); - kdc.createPrincipal(keytabClient, principalClientNoRealm); - - File keytabServer = new File(kerberosWorkDir.getRoot(), "bookkeeperserver.keytab"); - kdc.createPrincipal(keytabServer, principalServerNoRealm); - - File jaasFile = new File(kerberosWorkDir.getRoot(), "jaas.conf"); - try (FileWriter writer = new FileWriter(jaasFile)) { - writer.write("\n" - + "Bookie {\n" - + " com.sun.security.auth.module.Krb5LoginModule required debug=true\n" - + " useKeyTab=true\n" - + " keyTab=\"" + keytabServer.getAbsolutePath() + "\n" - + " storeKey=true\n" - + " useTicketCache=false\n" // won't test useTicketCache=true on JUnit tests - + " principal=\"" + principalServer + "\";\n" - + "};\n" - + "\n" - + "\n" - + "\n" - + "BookKeeper {\n" - + " com.sun.security.auth.module.Krb5LoginModule required debug=true\n" - + " useKeyTab=true\n" - + " keyTab=\"" + keytabClient.getAbsolutePath() + "\n" - + " storeKey=true\n" - + " useTicketCache=false\n" - + " principal=\"" + principalClient + "\";\n" - + "};\n" - ); - - } - - File krb5file = new File(kerberosWorkDir.getRoot(), "krb5.conf"); - try (FileWriter writer = new FileWriter(krb5file)) { - String conf = "[libdefaults]\n" - + " default_realm = " + kdc.getRealm() + "\n" - + " udp_preference_limit = 1\n" // force use TCP - + "\n" - + "\n" - + "[realms]\n" - + " " + kdc.getRealm() + " = {\n" - + " kdc = " + kdc.getHost() + ":" + kdc.getPort() + "\n" - + " }"; - writer.write(conf); - LOG.info("krb5.conf:\n" + conf); - } - - System.setProperty("java.security.auth.login.config", jaasFile.getAbsolutePath()); - System.setProperty("java.security.krb5.conf", krb5file.getAbsolutePath()); - javax.security.auth.login.Configuration.getConfiguration().refresh(); - - } - - @AfterClass - public static void stopMiniKdc() { - System.clearProperty("java.security.auth.login.config"); - System.clearProperty("java.security.krb5.conf"); - if (kdc != null) { - kdc.stop(); - } - } - - public GSSAPIBookKeeperTest() { - super(0); // start them later when auth providers are configured - } - - // we pass in ledgerId because the method may throw exceptions - private void connectAndWriteToBookie(ClientConfiguration conf, AtomicLong ledgerWritten) - throws BKException, InterruptedException, IOException, KeeperException { - LOG.info("Connecting to bookie"); - try (BookKeeper bkc = new BookKeeper(conf, zkc)) { - LedgerHandle l = bkc.createLedger(1, 1, DigestType.CRC32, - PASSWD); - ledgerWritten.set(l.getId()); - l.addEntry(ENTRY); - l.close(); - } - } - - /** - * check if the entry exists. Restart the bookie to allow access - */ - private int entryCount(long ledgerId, ClientConfiguration clientConf) - throws Exception { - LOG.info("Counting entries in {}", ledgerId); - clientConf.setClientAuthProviderFactoryClass( - SASLClientProviderFactory.class.getName()); - - restartBookies(c -> { - c.setUseHostNameAsBookieID(true); - c.setBookieAuthProviderFactoryClass( - SASLBookieAuthProviderFactory.class.getName()); - return c; - }); - - try (BookKeeper bkc = new BookKeeper(clientConf, zkc); - LedgerHandle lh = bkc.openLedger(ledgerId, DigestType.CRC32, - PASSWD)) { - if (lh.getLastAddConfirmed() < 0) { - return 0; - } - Enumeration e = lh.readEntries(0, lh.getLastAddConfirmed()); - int count = 0; - while (e.hasMoreElements()) { - count++; - assertTrue("Should match what we wrote", - Arrays.equals(e.nextElement().getEntry(), ENTRY)); - } - return count; - } - } - - /** - * Test an connection will authorize with a single message to the server and a single response. - */ - @Test - public void testSingleMessageAuth() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setUseHostNameAsBookieID(true); - bookieConf.setBookieAuthProviderFactoryClass( - SASLBookieAuthProviderFactory.class.getName()); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SASLClientProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - connectAndWriteToBookie(clientConf, ledgerId); // should succeed - - assertFalse(ledgerId.get() == -1); - assertEquals("Should have entry", 1, entryCount(ledgerId.get(), clientConf)); - } - - @Test - public void testNotAllowedClientId() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setUseHostNameAsBookieID(true); - bookieConf.setBookieAuthProviderFactoryClass( - SASLBookieAuthProviderFactory.class.getName()); - bookieConf.setProperty(SaslConstants.JAAS_CLIENT_ALLOWED_IDS, "nobody"); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SASLClientProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - try { - connectAndWriteToBookie(clientConf, ledgerId); - fail("should not be able to access the bookie"); - } catch (BKUnauthorizedAccessException err) { - } - - } - - BookieServer startAndStoreBookie(ServerConfiguration conf) throws Exception { - System.setProperty(SaslConstants.SASL_SERVICE_NAME, non_default_sasl_service_name); - return startAndAddBookie(conf).getServer(); - } - - @AfterClass - public static void resetJAAS() { - System.clearProperty("java.security.auth.login.config"); - Configuration.getConfiguration().refresh(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MD5DigestBookKeeperTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MD5DigestBookKeeperTest.java deleted file mode 100644 index a12b532a489..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MD5DigestBookKeeperTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF 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. -* -*/ -package org.apache.bookkeeper.sasl; - -import static org.apache.bookkeeper.sasl.SaslConstants.JAAS_CLIENT_ALLOWED_IDS; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.concurrent.atomic.AtomicLong; -import javax.security.auth.login.Configuration; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.AfterClass; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * MD5 digest test. - */ -public class MD5DigestBookKeeperTest extends BookKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(MD5DigestBookKeeperTest.class); - - private static final byte[] PASSWD = "testPasswd".getBytes(); - private static final byte[] ENTRY = "TestEntry".getBytes(); - - static { - System.setProperty("java.security.auth.login.config", - new File("src/test/resources/jaas_md5.conf").getAbsolutePath()); - } - - public MD5DigestBookKeeperTest() { - super(0); // start them later when auth providers are configured - } - - // we pass in ledgerId because the method may throw exceptions - private void connectAndWriteToBookie(ClientConfiguration conf, AtomicLong ledgerWritten) - throws Exception { - LOG.info("Connecting to bookie"); - BookKeeper bkc = new BookKeeper(conf, zkc); - LedgerHandle l = bkc.createLedger(1, 1, DigestType.CRC32, - PASSWD); - ledgerWritten.set(l.getId()); - l.addEntry(ENTRY); - l.close(); - bkc.close(); - } - - /** - * check if the entry exists. Restart the bookie to allow access - */ - private int entryCount(long ledgerId, ServerConfiguration bookieConf, - ClientConfiguration clientConf) throws Exception { - LOG.info("Counting entries in {}", ledgerId); - clientConf.setClientAuthProviderFactoryClass( - SASLClientProviderFactory.class.getName()); - - restartBookies(c -> { - c.setBookieAuthProviderFactoryClass( - SASLBookieAuthProviderFactory.class.getName()); - c.setProperty(JAAS_CLIENT_ALLOWED_IDS, ".*hd.*"); - return c; - }); - - try (BookKeeper bkc = new BookKeeper(clientConf, zkc); - LedgerHandle lh = bkc.openLedger(ledgerId, DigestType.CRC32, - PASSWD)) { - - if (lh.getLastAddConfirmed() < 0) { - return 0; - } - Enumeration e = lh.readEntries(0, lh.getLastAddConfirmed()); - int count = 0; - while (e.hasMoreElements()) { - count++; - assertTrue("Should match what we wrote", - Arrays.equals(e.nextElement().getEntry(), ENTRY)); - } - return count; - } - } - - /** - * Test an connection will authorize with a single message to the server and a single response. - */ - @Test - public void testSingleMessageAuth() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setBookieAuthProviderFactoryClass( - SASLBookieAuthProviderFactory.class.getName()); - bookieConf.setProperty(JAAS_CLIENT_ALLOWED_IDS, ".*hd.*"); - - ClientConfiguration clientConf = newClientConfiguration(); - clientConf.setClientAuthProviderFactoryClass( - SASLClientProviderFactory.class.getName()); - - startAndStoreBookie(bookieConf); - - AtomicLong ledgerId = new AtomicLong(-1); - connectAndWriteToBookie(clientConf, ledgerId); // should succeed - - assertFalse(ledgerId.get() == -1); - assertEquals("Should have entry", 1, entryCount(ledgerId.get(), bookieConf, clientConf)); - } - - BookieServer startAndStoreBookie(ServerConfiguration conf) throws Exception { - return startAndAddBookie(conf).getServer(); - } - - @AfterClass - public static void resetJAAS() { - System.clearProperty("java.security.auth.login.config"); - Configuration.getConfiguration().refresh(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MiniKdc.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MiniKdc.java deleted file mode 100644 index 42b0fd85c1e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MiniKdc.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.sasl; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import org.apache.kerby.kerberos.kerb.KrbException; -import org.apache.kerby.kerberos.kerb.server.KdcConfigKey; -import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer; -import org.apache.kerby.util.IOUtil; -import org.apache.kerby.util.NetworkUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Mini KDC based on Apache Directory Server that can be embedded in testcases - * or used from command line as a standalone KDC. - * - *

From within testcases: - * - *

MiniKdc sets one System property when started and un-set when stopped: - *

    - *
  • sun.security.krb5.debug: set to the debug value provided in the - * configuration
  • - *
- * Because of this, multiple MiniKdc instances cannot be started in parallel. - * For example, running testcases in parallel that start a KDC each. To - * accomplish this a single MiniKdc should be used for all testcases running - * in parallel. - * - *

MiniKdc default configuration values are: - *

    - *
  • org.name=EXAMPLE (used to create the REALM)
  • - *
  • org.domain=COM (used to create the REALM)
  • - *
  • kdc.bind.address=localhost
  • - *
  • kdc.port=0 (ephemeral port)
  • - *
  • instance=DefaultKrbServer
  • - *
  • max.ticket.lifetime=86400000 (1 day)
  • - *
  • max.renewable.lifetime=604800000 (7 days)
  • - *
  • transport=TCP
  • - *
  • debug=false
  • - *
- * The generated krb5.conf forces TCP connections. - * This code is originally from HDFS, see the file name MiniKdc there - * in case of bug fixing, history, etc. - * https://github.com/apache/hadoop/blob/trunk/hadoop-common-project/hadoop-minikdc/src/main/java/org/apache/hadoop/minikdc/MiniKdc.java - */ -public class MiniKdc { - - public static final String JAVA_SECURITY_KRB5_CONF = - "java.security.krb5.conf"; - public static final String SUN_SECURITY_KRB5_DEBUG = - "sun.security.krb5.debug"; - - - private static final Logger LOG = LoggerFactory.getLogger(MiniKdc.class); - - public static final String ORG_NAME = "org.name"; - public static final String ORG_DOMAIN = "org.domain"; - public static final String KDC_BIND_ADDRESS = "kdc.bind.address"; - public static final String KDC_PORT = "kdc.port"; - public static final String INSTANCE = "instance"; - public static final String MAX_TICKET_LIFETIME = "max.ticket.lifetime"; - public static final String MAX_RENEWABLE_LIFETIME = "max.renewable.lifetime"; - public static final String TRANSPORT = "transport"; - public static final String DEBUG = "debug"; - - private static final Set PROPERTIES = new HashSet(); - private static final Properties DEFAULT_CONFIG = new Properties(); - - static { - PROPERTIES.add(ORG_NAME); - PROPERTIES.add(ORG_DOMAIN); - PROPERTIES.add(KDC_BIND_ADDRESS); - PROPERTIES.add(KDC_BIND_ADDRESS); - PROPERTIES.add(KDC_PORT); - PROPERTIES.add(INSTANCE); - PROPERTIES.add(TRANSPORT); - PROPERTIES.add(MAX_TICKET_LIFETIME); - PROPERTIES.add(MAX_RENEWABLE_LIFETIME); - - DEFAULT_CONFIG.setProperty(KDC_BIND_ADDRESS, "localhost"); - DEFAULT_CONFIG.setProperty(KDC_PORT, "0"); - DEFAULT_CONFIG.setProperty(INSTANCE, "DefaultKrbServer"); - DEFAULT_CONFIG.setProperty(ORG_NAME, "EXAMPLE"); - DEFAULT_CONFIG.setProperty(ORG_DOMAIN, "COM"); - DEFAULT_CONFIG.setProperty(TRANSPORT, "TCP"); - DEFAULT_CONFIG.setProperty(MAX_TICKET_LIFETIME, "86400000"); - DEFAULT_CONFIG.setProperty(MAX_RENEWABLE_LIFETIME, "604800000"); - DEFAULT_CONFIG.setProperty(DEBUG, "false"); - } - - /** - * Convenience method that returns MiniKdc default configuration. - * - *

The returned configuration is a copy, it can be customized before using - * it to create a MiniKdc. - * @return a MiniKdc default configuration. - */ - public static Properties createConf() { - return (Properties) DEFAULT_CONFIG.clone(); - } - - private Properties conf; - private SimpleKdcServer simpleKdc; - private int port; - private String realm; - private File workDir; - private File krb5conf; - private String transport; - private boolean krb5Debug; - - public void setTransport(String transport) { - this.transport = transport; - } - - /** - * Creates a MiniKdc. - * - * @param conf MiniKdc configuration. - * @param workDir working directory, it should be the build directory. Under - * this directory an ApacheDS working directory will be created, this - * directory will be deleted when the MiniKdc stops. - * @throws Exception thrown if the MiniKdc could not be created. - */ - public MiniKdc(Properties conf, File workDir) throws Exception { - if (!conf.keySet().containsAll(PROPERTIES)) { - Set missingProperties = new HashSet(PROPERTIES); - missingProperties.removeAll(conf.keySet()); - throw new IllegalArgumentException("Missing configuration properties: " - + missingProperties); - } - this.workDir = new File(workDir, Long.toString(System.currentTimeMillis())); - if (!this.workDir.exists() - && !this.workDir.mkdirs()) { - throw new RuntimeException("Cannot create directory " + this.workDir); - } - LOG.info("Configuration:"); - LOG.info("---------------------------------------------------------------"); - for (Map.Entry entry : conf.entrySet()) { - LOG.info(" {}: {}", entry.getKey(), entry.getValue()); - } - LOG.info("---------------------------------------------------------------"); - this.conf = conf; - port = Integer.parseInt(conf.getProperty(KDC_PORT)); - String orgName = conf.getProperty(ORG_NAME); - String orgDomain = conf.getProperty(ORG_DOMAIN); - realm = orgName.toUpperCase(Locale.ENGLISH) + "." - + orgDomain.toUpperCase(Locale.ENGLISH); - } - - /** - * Returns the port of the MiniKdc. - * - * @return the port of the MiniKdc. - */ - public int getPort() { - return port; - } - - /** - * Returns the host of the MiniKdc. - * - * @return the host of the MiniKdc. - */ - public String getHost() { - return conf.getProperty(KDC_BIND_ADDRESS); - } - - /** - * Returns the realm of the MiniKdc. - * - * @return the realm of the MiniKdc. - */ - public String getRealm() { - return realm; - } - - public File getKrb5conf() { - krb5conf = new File(System.getProperty(JAVA_SECURITY_KRB5_CONF)); - return krb5conf; - } - - /** - * Starts the MiniKdc. - * - * @throws Exception thrown if the MiniKdc could not be started. - */ - public synchronized void start() throws Exception { - if (simpleKdc != null) { - throw new RuntimeException("Already started"); - } - simpleKdc = new SimpleKdcServer(); - prepareKdcServer(); - simpleKdc.init(); - resetDefaultRealm(); - simpleKdc.start(); - LOG.info("MiniKdc stated."); - } - - private void resetDefaultRealm() throws IOException { - InputStream templateResource = new FileInputStream( - getKrb5conf().getAbsolutePath()); - String content = IOUtil.readInput(templateResource); - content = content.replaceAll("default_realm = .*\n", - "default_realm = " + getRealm() + "\n"); - IOUtil.writeFile(content, getKrb5conf()); - } - - private void prepareKdcServer() throws Exception { - // transport - simpleKdc.setWorkDir(workDir); - simpleKdc.setKdcHost(getHost()); - simpleKdc.setKdcRealm(realm); - if (transport == null) { - transport = conf.getProperty(TRANSPORT); - } - if (port == 0) { - port = NetworkUtil.getServerPort(); - } - if (transport != null) { - if (transport.trim().equals("TCP")) { - simpleKdc.setKdcTcpPort(port); - simpleKdc.setAllowUdp(false); - } else if (transport.trim().equals("UDP")) { - simpleKdc.setKdcUdpPort(port); - simpleKdc.setAllowTcp(false); - } else { - throw new IllegalArgumentException("Invalid transport: " + transport); - } - } else { - throw new IllegalArgumentException("Need to set transport!"); - } - simpleKdc.getKdcConfig().setString(KdcConfigKey.KDC_SERVICE_NAME, - conf.getProperty(INSTANCE)); - if (conf.getProperty(DEBUG) != null) { - krb5Debug = getAndSet(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG)); - } - } - - /** - * Stops the MiniKdc. - */ - public synchronized void stop() { - if (simpleKdc != null) { - try { - simpleKdc.stop(); - } catch (KrbException e) { - e.printStackTrace(); - } finally { - if (conf.getProperty(DEBUG) != null) { - System.setProperty(SUN_SECURITY_KRB5_DEBUG, - Boolean.toString(krb5Debug)); - } - } - } - delete(workDir); - try { - // Will be fixed in next Kerby version. - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - LOG.info("MiniKdc stopped."); - } - - private void delete(File f) { - if (f.isFile()) { - if (!f.delete()) { - LOG.warn("WARNING: cannot delete file " + f.getAbsolutePath()); - } - } else { - for (File c: f.listFiles()) { - delete(c); - } - if (!f.delete()) { - LOG.warn("WARNING: cannot delete directory " + f.getAbsolutePath()); - } - } - } - - /** - * Creates a principal in the KDC with the specified user and password. - * - * @param principal principal name, do not include the domain. - * @param password password. - * @throws Exception thrown if the principal could not be created. - */ - public synchronized void createPrincipal(String principal, String password) - throws Exception { - simpleKdc.createPrincipal(principal, password); - } - - /** - * Creates multiple principals in the KDC and adds them to a keytab file. - * - * @param keytabFile keytab file to add the created principals. - * @param principals principals to add to the KDC, do not include the domain. - * @throws Exception thrown if the principals or the keytab file could not be - * created. - */ - public synchronized void createPrincipal(File keytabFile, - String ... principals) - throws Exception { - simpleKdc.createPrincipals(principals); - if (keytabFile.exists() && !keytabFile.delete()) { - LOG.error("Failed to delete keytab file: " + keytabFile); - } - for (String principal : principals) { - simpleKdc.getKadmin().exportKeytab(keytabFile, principal); - } - } - - /** - * Set the System property; return the old value for caching. - * - * @param sysprop property - * @param debug true or false - * @return the previous value - */ - private boolean getAndSet(String sysprop, String debug) { - boolean old = Boolean.getBoolean(sysprop); - System.setProperty(sysprop, debug); - return old; - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestBookieBoot.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestBookieBoot.java deleted file mode 100644 index 62567bd5502..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestBookieBoot.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.server; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import java.io.File; -import java.net.Socket; -import java.util.Iterator; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.ExitCode; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.util.PortManager; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests that a bookie can boot via the main method - * and serve read and write requests. - */ -public class TestBookieBoot extends BookKeeperClusterTestCase { - private static final Logger log = LoggerFactory.getLogger(TestBookieBoot.class); - public TestBookieBoot() throws Exception { - super(0); - } - - @Test - public void testBootFromConfig() throws Exception { - ServerConfiguration conf = new ServerConfiguration(); - conf.setMetadataServiceUri(this.metadataServiceUri); - conf.setAllowLoopback(true); - conf.setBookiePort(PortManager.nextFreePort()); - conf.setLedgerStorageClass("org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage"); - - File storageDir = tmpDirs.createNew("bookie", "storage"); - conf.setLedgerDirNames(new String[] { storageDir.toString() }); - conf.setJournalDirName(storageDir.toString()); - - PropertiesConfiguration propsConf = new PropertiesConfiguration(); - for (Iterator iter = conf.getKeys(); iter.hasNext(); ) { - String key = iter.next(); - propsConf.setProperty(key, conf.getProperty(key)); - } - - File confFile = File.createTempFile("test", "conf"); - propsConf.save(confFile); - - log.info("Conf: {}", confFile); - - CompletableFuture promise = new CompletableFuture<>(); - Thread t = new Thread(() -> { - try { - int ret = Main.doMain(new String[] {"-c", confFile.toString()}); - promise.complete(ret); - } catch (Exception e) { - promise.completeExceptionally(e); - } - }, "bookie-main"); - t.start(); - - BookieSocketAddress addr = BookieImpl.getBookieAddress(conf); - BookKeeperTestClient bkc = new BookKeeperTestClient(baseClientConf); - bkc.waitForWritableBookie(addr.toBookieId()).get(); - - boolean connected = false; - for (int i = 0; i < 100 && t.isAlive(); i++) { - try (Socket s = new Socket(addr.getSocketAddress().getAddress(), addr.getPort())) { - connected = true; - break; - } catch (Exception e) { - // expected, will retry - } - Thread.sleep(100); - } - assertThat(connected, equalTo(true)); - - long ledgerId; - try (WriteHandle wh = bkc.newCreateLedgerOp().withEnsembleSize(1) - .withWriteQuorumSize(1).withAckQuorumSize(1) - .withDigestType(DigestType.CRC32C) - .withPassword(new byte[0]) - .execute().get()) { - ledgerId = wh.getId(); - wh.append("foobar".getBytes(UTF_8)); - } - - try (ReadHandle rh = bkc.newOpenLedgerOp().withLedgerId(ledgerId) - .withDigestType(DigestType.CRC32C) - .withPassword(new byte[0]) - .withRecovery(true) - .execute().get()) { - assertThat(rh.getLastAddConfirmed(), equalTo(0L)); - try (LedgerEntries entries = rh.read(0, 0)) { - assertThat(new String(entries.getEntry(0).getEntryBytes(), UTF_8), equalTo("foobar")); - } - } - - t.interrupt(); - assertThat(promise.get(10, TimeUnit.SECONDS), equalTo(ExitCode.OK)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestEmbeddedServer.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestEmbeddedServer.java deleted file mode 100644 index 60b43032ab7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestEmbeddedServer.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.server; - -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.LD_INDEX_SCOPE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.LD_LEDGER_SCOPE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import lombok.Cleanup; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieResources; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.LegacyCookieValidation; -import org.apache.bookkeeper.bookie.UncleanShutdownDetectionImpl; -import org.apache.bookkeeper.common.allocator.ByteBufAllocatorWithOomHandler; -import org.apache.bookkeeper.common.component.LifecycleComponentStack; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.NullMetadataBookieDriver; -import org.apache.bookkeeper.meta.NullMetadataBookieDriver.NullLedgerManagerFactory; -import org.apache.bookkeeper.meta.NullMetadataBookieDriver.NullRegistrationManager; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.server.component.ServerLifecycleComponent; -import org.apache.bookkeeper.server.conf.BookieConfiguration; -import org.apache.bookkeeper.stats.NullStatsProvider; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.stats.StatsProvider; -import org.apache.bookkeeper.util.DiskChecker; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test of {@link EmbeddedServer}. - */ -@RunWith(MockitoJUnitRunner.class) -public class TestEmbeddedServer { - - static class TestComponent extends ServerLifecycleComponent { - - public TestComponent(BookieConfiguration conf, StatsLogger statsLogger) { - super("test-component", conf, statsLogger); - } - - @Override - protected void doStart() { - } - - @Override - protected void doStop() { - } - - @Override - protected void doClose() throws IOException { - } - - } - - @Test - public void testBuildBookieServer() throws Exception { - @Cleanup - MockedStatic bookieResourcesMockedStatic = mockStatic(BookieResources.class, - CALLS_REAL_METHODS); - bookieResourcesMockedStatic.when(() -> - BookieResources.createMetadataDriver(any(), any())).thenReturn(new NullMetadataBookieDriver()); - bookieResourcesMockedStatic.when(() -> - BookieResources.createAllocator(any())).thenReturn(mock(ByteBufAllocatorWithOomHandler.class)); - - ServerConfiguration serverConf = new ServerConfiguration() - .setAllowLoopback(true) - .setAutoRecoveryDaemonEnabled(false) - .setHttpServerEnabled(false) - .setExtraServerComponents(new String[] { TestComponent.class.getName() }); - BookieConfiguration conf = new BookieConfiguration(serverConf); - - @Cleanup - MockedStatic legacyCookieValidationMockedStatic = - mockStatic(LegacyCookieValidation.class); - legacyCookieValidationMockedStatic.when(() -> LegacyCookieValidation.newLegacyCookieValidation(any(), any())) - .thenReturn(mock(LegacyCookieValidation.class)); - - @Cleanup - MockedStatic bookieMockedStatic = mockStatic(BookieImpl.class, CALLS_REAL_METHODS); - bookieMockedStatic.when(() -> BookieImpl.newBookieImpl(any(), any(), any(), any(), any(), any(), any(), - any(), any())).thenReturn(mock(BookieImpl.class)); - - BookieServer mockServer = mock(BookieServer.class); - - BookieSocketAddress bookieAddress = new BookieSocketAddress("127.0.0.1", 1281); - when(mockServer.getLocalAddress()).thenReturn(bookieAddress); - - @Cleanup - MockedStatic bookieServerMockedStatic = mockStatic(BookieServer.class); - bookieServerMockedStatic.when(() -> BookieServer.newBookieServer(any(), any(), any(), any(), any())) - .thenReturn(mockServer); - - EmbeddedServer server = EmbeddedServer.builder(conf).build(); - LifecycleComponentStack stack = server.getLifecycleComponentStack(); - assertEquals(7, stack.getNumComponents()); - assertTrue(stack.getComponent(6) instanceof TestComponent); - - stack.start(); - verify(mockServer, times(1)).start(); - - stack.stop(); - - stack.close(); - verify(mockServer, times(1)).shutdown(); - } - - @Test - public void testBuildBookieServerCustomComponents() throws Exception { - - ServerConfiguration serverConf = new ServerConfiguration() - .setAllowLoopback(true) - .setAutoRecoveryDaemonEnabled(false) - .setHttpServerEnabled(false) - .setExtraServerComponents(new String[]{TestComponent.class.getName()}); - BookieConfiguration conf = new BookieConfiguration(serverConf); - - StatsProvider statsProvider = new NullStatsProvider(); - StatsLogger rootStatsLogger = statsProvider.getStatsLogger(""); - RegistrationManager registrationManager = new NullRegistrationManager(); - LedgerManagerFactory ledgerManagerFactory = new NullLedgerManagerFactory(); - - DiskChecker diskChecker = BookieResources.createDiskChecker(serverConf); - - LedgerDirsManager ledgerDirsManager = BookieResources.createLedgerDirsManager( - conf.getServerConf(), diskChecker, rootStatsLogger.scope(LD_LEDGER_SCOPE)); - - LedgerDirsManager indexDirsManager = BookieResources.createIndexDirsManager( - conf.getServerConf(), diskChecker, rootStatsLogger.scope(LD_INDEX_SCOPE), ledgerDirsManager); - - UncleanShutdownDetectionImpl uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - - ByteBufAllocatorWithOomHandler byteBufFromResources = mock(ByteBufAllocatorWithOomHandler.class); - ByteBufAllocatorWithOomHandler byteBuf = mock(ByteBufAllocatorWithOomHandler.class); - - @Cleanup - MockedStatic bookieResourcesMockedStatic = mockStatic(BookieResources.class); - bookieResourcesMockedStatic.when(() -> - BookieResources.createMetadataDriver(any(), any())).thenReturn(new NullMetadataBookieDriver()); - bookieResourcesMockedStatic.when(() -> - BookieResources.createAllocator(any())).thenReturn(byteBufFromResources); - - @Cleanup - MockedStatic legacyCookieValidationMockedStatic = - mockStatic(LegacyCookieValidation.class); - legacyCookieValidationMockedStatic.when(() -> LegacyCookieValidation.newLegacyCookieValidation(any(), any())) - .thenReturn(mock(LegacyCookieValidation.class)); - - @Cleanup - MockedStatic bookieMockedStatic = mockStatic(BookieImpl.class, CALLS_REAL_METHODS); - bookieMockedStatic.when(() -> BookieImpl.newBookieImpl(any(), any(), any(), any(), any(), any(), any(), any(), - any())).thenReturn(mock(BookieImpl.class)); - - BookieServer mockServer = mock(BookieServer.class); - - @Cleanup - MockedStatic bookieServerMockedStatic = mockStatic(BookieServer.class); - bookieServerMockedStatic.when(() -> BookieServer.newBookieServer(any(), any(), any(), any(), any())) - .thenReturn(mockServer); - - BookieSocketAddress bookieAddress = new BookieSocketAddress("127.0.0.1", 1281); - when(mockServer.getLocalAddress()).thenReturn(bookieAddress); - - EmbeddedServer server = EmbeddedServer.builder(conf) - .statsProvider(statsProvider) - .registrationManager(registrationManager) - .ledgerManagerFactory(ledgerManagerFactory) - .diskChecker(diskChecker) - .ledgerDirsManager(ledgerDirsManager) - .indexDirsManager(indexDirsManager) - .allocator(byteBuf) - .uncleanShutdownDetection(uncleanShutdownDetection) - .build(); - - assertSame(statsProvider, server.getStatsProvider()); - assertSame(registrationManager, server.getRegistrationManager()); - assertSame(ledgerManagerFactory, server.getLedgerManagerFactory()); - assertSame(diskChecker, server.getDiskChecker()); - assertSame(ledgerDirsManager, server.getLedgerDirsManager()); - assertSame(indexDirsManager, server.getIndexDirsManager()); - - LifecycleComponentStack stack = server.getLifecycleComponentStack(); - assertEquals(3, stack.getNumComponents()); - assertTrue(stack.getComponent(2) instanceof TestComponent); - - stack.start(); - verify(mockServer, times(1)).start(); - - stack.stop(); - - stack.close(); - verify(mockServer, times(1)).shutdown(); - } - - @Test - public void testIgnoreExtraServerComponentsStartupFailures() throws Exception { - @Cleanup - MockedStatic bookieResourcesMockedStatic = mockStatic(BookieResources.class, - CALLS_REAL_METHODS); - bookieResourcesMockedStatic.when(() -> - BookieResources.createMetadataDriver(any(), any())).thenReturn(new NullMetadataBookieDriver()); - - ServerConfiguration serverConf = new ServerConfiguration() - .setAllowLoopback(true) - .setAutoRecoveryDaemonEnabled(false) - .setHttpServerEnabled(false) - .setExtraServerComponents(new String[] { "bad-server-component"}) - .setIgnoreExtraServerComponentsStartupFailures(true); - BookieConfiguration conf = new BookieConfiguration(serverConf); - - @Cleanup - MockedStatic legacyCookieValidationMockedStatic = - mockStatic(LegacyCookieValidation.class); - legacyCookieValidationMockedStatic.when(() -> LegacyCookieValidation.newLegacyCookieValidation(any(), any())) - .thenReturn(mock(LegacyCookieValidation.class)); - - @Cleanup - MockedStatic bookieMockedStatic = mockStatic(BookieImpl.class, CALLS_REAL_METHODS); - bookieMockedStatic.when(() -> BookieImpl.newBookieImpl(any(), any(), any(), any(), any(), any(), any(), any(), - any())).thenReturn(mock(BookieImpl.class)); - - BookieServer mockServer = mock(BookieServer.class); - - @Cleanup - MockedStatic bookieServerMockedStatic = mockStatic(BookieServer.class); - bookieServerMockedStatic.when(() -> BookieServer.newBookieServer(any(), any(), any(), any(), any())) - .thenReturn(mockServer); - - BookieSocketAddress bookieAddress = new BookieSocketAddress("127.0.0.1", 1281); - when(mockServer.getLocalAddress()).thenReturn(bookieAddress); - - LifecycleComponentStack stack = EmbeddedServer.builder(conf).build().getLifecycleComponentStack(); - assertEquals(6, stack.getNumComponents()); - - stack.start(); - verify(mockServer, times(1)).start(); - - stack.stop(); - - stack.close(); - verify(mockServer, times(1)).shutdown(); - } - - @Test - public void testExtraServerComponentsStartupFailures() throws Exception { - @Cleanup - MockedStatic bookieResourcesMockedStatic = mockStatic(BookieResources.class, - CALLS_REAL_METHODS); - bookieResourcesMockedStatic.when(() -> - BookieResources.createMetadataDriver(any(), any())).thenReturn(new NullMetadataBookieDriver()); - - ServerConfiguration serverConf = new ServerConfiguration() - .setAllowLoopback(true) - .setAutoRecoveryDaemonEnabled(false) - .setHttpServerEnabled(false) - .setExtraServerComponents(new String[] { "bad-server-component"}) - .setIgnoreExtraServerComponentsStartupFailures(false); - BookieConfiguration conf = new BookieConfiguration(serverConf); - - @Cleanup - MockedStatic legacyCookieValidationMockedStatic = - mockStatic(LegacyCookieValidation.class); - legacyCookieValidationMockedStatic.when(() -> LegacyCookieValidation.newLegacyCookieValidation(any(), any())) - .thenReturn(mock(LegacyCookieValidation.class)); - - @Cleanup - MockedStatic bookieMockedStatic = mockStatic(BookieImpl.class, CALLS_REAL_METHODS); - bookieMockedStatic.when(() -> BookieImpl.newBookieImpl(any(), any(), any(), any(), any(), any(), any(), any(), - any())).thenReturn(mock(BookieImpl.class)); - - BookieServer mockServer = mock(BookieServer.class); - - @Cleanup - MockedStatic bookieServerMockedStatic = mockStatic(BookieServer.class); - bookieServerMockedStatic.when(() -> BookieServer.newBookieServer(any(), any(), any(), any(), any())) - .thenReturn(mockServer); - - try { - EmbeddedServer.builder(conf).build().getLifecycleComponentStack(); - fail("Should fail to start bookie server if `ignoreExtraServerComponentsStartupFailures` is set to false"); - } catch (RuntimeException re) { - assertTrue(re.getCause() instanceof ClassNotFoundException); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/component/TestServerLifecycleComponent.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/component/TestServerLifecycleComponent.java deleted file mode 100644 index 8a1153f509a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/component/TestServerLifecycleComponent.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.server.component; - -import static org.apache.bookkeeper.server.component.ServerLifecycleComponent.loadServerComponents; -import static org.apache.bookkeeper.server.component.ServerLifecycleComponent.newComponent; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.List; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.server.conf.BookieConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.junit.Test; - -/** - * Manage the test server lifecycle. - */ -public class TestServerLifecycleComponent { - - static class TestComponent extends ServerLifecycleComponent { - - public TestComponent(BookieConfiguration conf, StatsLogger statsLogger) { - super("test-component", conf, statsLogger); - } - - @Override - protected void doStart() { - // no-op - } - - @Override - protected void doStop() { - // no-op - } - - @Override - protected void doClose() throws IOException { - // no-op - } - } - - static class TestComponent2 extends TestComponent { - public TestComponent2(BookieConfiguration conf, StatsLogger statsLogger) { - super(conf, statsLogger); - } - } - - @Test - public void testNewComponent() throws Exception { - BookieConfiguration conf = new BookieConfiguration(new ServerConfiguration()); - StatsLogger statsLogger = NullStatsLogger.INSTANCE; - ServerLifecycleComponent component = newComponent( - TestComponent.class, - conf, - statsLogger); - assertEquals("test-component", component.getName()); - assertEquals(conf, component.getConf()); - } - - @Test - public void testLoadServerComponents() throws Exception { - BookieConfiguration conf = new BookieConfiguration(new ServerConfiguration()); - StatsLogger statsLogger = NullStatsLogger.INSTANCE; - String[] clsNames = new String[] { - TestComponent.class.getName(), - TestComponent2.class.getName() - }; - List components = loadServerComponents( - clsNames, - conf, - statsLogger); - assertEquals(2, components.size()); - assertTrue(components.get(0) instanceof TestComponent); - assertTrue(components.get(1) instanceof TestComponent2); - } - - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java deleted file mode 100644 index 847c1118f5c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java +++ /dev/null @@ -1,1179 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.server.http; - -import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.util.concurrent.UncheckedExecutionException; -import java.io.File; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Future; -import lombok.Cleanup; -import org.apache.bookkeeper.bookie.BookieResources; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.ClientUtil; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.common.util.JsonUtil; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.http.HttpServer; -import org.apache.bookkeeper.http.service.HttpEndpointService; -import org.apache.bookkeeper.http.service.HttpServiceRequest; -import org.apache.bookkeeper.http.service.HttpServiceResponse; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.replication.AuditorElector; -import org.apache.bookkeeper.server.http.service.BookieInfoService; -import org.apache.bookkeeper.server.http.service.BookieSanityService; -import org.apache.bookkeeper.server.http.service.BookieSanityService.BookieSanity; -import org.apache.bookkeeper.server.http.service.BookieStateReadOnlyService.ReadOnlyState; -import org.apache.bookkeeper.server.http.service.BookieStateService.BookieState; -import org.apache.bookkeeper.server.http.service.ClusterInfoService; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the HTTP service. - */ -public class TestHttpService extends BookKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestHttpService.class); - - private BKHttpServiceProvider bkHttpServiceProvider; - private static final int numberOfBookies = 6; - - public TestHttpService() { - super(numberOfBookies); - try { - File tmpDir = tmpDirs.createNew("bookie_http", "test"); - baseConf.setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames( - new String[]{tmpDir.getPath()}); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - baseClientConf.setStoreSystemtimeAsLedgerCreationTime(true); - - MetadataBookieDriver metadataDriver = BookieResources.createMetadataDriver( - baseConf, NullStatsLogger.INSTANCE); - - this.bkHttpServiceProvider = new BKHttpServiceProvider.Builder() - .setBookieServer(serverByIndex(numberOfBookies - 1)) - .setServerConfiguration(baseConf) - .setLedgerManagerFactory(metadataDriver.getLedgerManagerFactory()) - .build(); - } - - @Test - public void testHeartbeatService() throws Exception { - // test heartbeat service - HttpEndpointService heartbeatService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.HEARTBEAT); - HttpServiceResponse response = heartbeatService.handle(null); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - assertEquals("OK\n", response.getBody()); - } - - @Test - public void testConfigServiceGet() throws Exception { - try { - // test config service - String testProperty = "TEST_PROPERTY"; - String testValue = "TEST_VALUE"; - baseConf.setProperty(testProperty, testValue); - HttpEndpointService configService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.SERVER_CONFIG); - HttpServiceRequest getRequest = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response = configService.handle(getRequest); - Map configMap = JsonUtil.fromJson( - response.getBody(), - Map.class - ); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - assertEquals(testValue, configMap.get(testProperty)); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Test - public void testConfigServicePut() throws Exception { - // test config service - HttpEndpointService configService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.SERVER_CONFIG); - // properties to be set - String putBody = "{\"TEST_PROPERTY1\": \"TEST_VALUE1\", \"TEST_PROPERTY2\": 2, \"TEST_PROPERTY3\": true }"; - - // null body, should return NOT_FOUND - HttpServiceRequest putRequest1 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse putResponse1 = configService.handle(putRequest1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), putResponse1.getStatusCode()); - - // Method DELETE, should return NOT_FOUND - HttpServiceRequest putRequest2 = new HttpServiceRequest(putBody, HttpServer.Method.DELETE, null); - HttpServiceResponse putResponse2 = configService.handle(putRequest2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), putResponse2.getStatusCode()); - - // Normal PUT, should success, then verify using get method - HttpServiceRequest putRequest3 = new HttpServiceRequest(putBody, HttpServer.Method.PUT, null); - HttpServiceResponse putResponse3 = configService.handle(putRequest3); - assertEquals(HttpServer.StatusCode.OK.getValue(), putResponse3.getStatusCode()); - - // Get all the config - HttpServiceRequest getRequest = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response = configService.handle(getRequest); - Map configMap = JsonUtil.fromJson( - response.getBody(), - Map.class - ); - - // verify response code - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - // verify response body - assertEquals("TEST_VALUE1", configMap.get("TEST_PROPERTY1")); - assertEquals("2", configMap.get("TEST_PROPERTY2")); - assertEquals("true", configMap.get("TEST_PROPERTY3")); - } - - @Test - public void testListBookiesService() throws Exception { - HttpEndpointService listBookiesService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LIST_BOOKIES); - - //1, null parameters, should print rw bookies, without hostname - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = listBookiesService.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - // get response , expected get 3 bookies, and without hostname - @SuppressWarnings("unchecked") - HashMap respBody = JsonUtil.fromJson(response1.getBody(), HashMap.class); - assertEquals(numberOfBookies, respBody.size()); - for (int i = 0; i < numberOfBookies; i++) { - assertEquals(true, respBody.containsKey(getBookie(i).toString())); - assertEquals(null, respBody.get(getBookie(i).toString())); - } - - //2, parameter: type=rw&print_hostnames=true, should print rw bookies with hostname - HashMap params = Maps.newHashMap(); - params.put("type", "rw"); - params.put("print_hostnames", "true"); - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, params); - HttpServiceResponse response2 = listBookiesService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - // get response , expected get numberOfBookies bookies, and with hostname - @SuppressWarnings("unchecked") - HashMap respBody2 = JsonUtil.fromJson(response2.getBody(), HashMap.class); - assertEquals(numberOfBookies, respBody2.size()); - for (int i = 0; i < numberOfBookies; i++) { - assertEquals(true, respBody2.containsKey(getBookie(i).toString())); - assertNotNull(respBody2.get(getBookie(i).toString())); - } - - //3, parameter: type=ro&print_hostnames=true, should print ro bookies with hostname - // turn bookie 1 into ro, get it - setBookieToReadOnly(getBookie(1)); - Thread.sleep(200); - HashMap params3 = Maps.newHashMap(); - params3.put("type", "ro"); - params3.put("print_hostnames", "true"); - HttpServiceRequest request3 = new HttpServiceRequest(null, HttpServer.Method.GET, params3); - HttpServiceResponse response3 = listBookiesService.handle(request3); - //LOG.info("Turn 1 bookies into RO, should get it in this request"); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - // get response , expected get 1 ro bookies, and with hostname - @SuppressWarnings("unchecked") - HashMap respBody3 = JsonUtil.fromJson(response3.getBody(), HashMap.class); - assertEquals(1, respBody3.size()); - assertEquals(true, respBody3.containsKey(getBookie(1).toString())); - - // get other 5 rw bookies. - HashMap params4 = Maps.newHashMap(); - params4.put("type", "rw"); - params4.put("print_hostnames", "true"); - HttpServiceRequest request4 = new HttpServiceRequest(null, HttpServer.Method.GET, params4); - HttpServiceResponse response4 = listBookiesService.handle(request4); - assertEquals(HttpServer.StatusCode.OK.getValue(), response4.getStatusCode()); - @SuppressWarnings("unchecked") - HashMap respBody4 = JsonUtil.fromJson(response4.getBody(), HashMap.class); - assertEquals(5, respBody4.size()); - assertEquals(true, respBody4.containsKey(getBookie(2).toString())); - } - - /** - * Create ledgers, then test ListLedgerService. - */ - @Test - public void testListLedgerService() throws Exception { - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 430; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "password".getBytes()); - } - - HttpEndpointService listLedgerService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LIST_LEDGER); - - //1, null parameters, should print ledger ids, without metadata - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = listLedgerService.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - // get response , expected get all ledgers, and without metadata - @SuppressWarnings("unchecked") - LinkedHashMap respBody = JsonUtil.fromJson(response1.getBody(), LinkedHashMap.class); - assertEquals(numLedgers, respBody.size()); - for (int i = 0; i < numLedgers; i++) { - assertEquals(true, respBody.containsKey(Long.valueOf(lh[i].getId()).toString())); - assertEquals(null, respBody.get(Long.valueOf(lh[i].getId()).toString())); - } - - //2, parameter: print_metadata=true, should print ledger ids, with metadata - HashMap params = Maps.newHashMap(); - params.put("print_metadata", "true"); - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, params); - HttpServiceResponse response2 = listLedgerService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - // get response, expected get all ledgers, and with metadata - @SuppressWarnings("unchecked") - LinkedHashMap respBody2 = JsonUtil.fromJson(response2.getBody(), LinkedHashMap.class); - assertEquals(numLedgers, respBody2.size()); - for (int i = 0; i < numLedgers; i++) { - assertEquals(true, respBody2.containsKey(Long.valueOf(lh[i].getId()).toString())); - assertNotNull(respBody2.get(Long.valueOf(lh[i].getId()).toString())); - } - - //3, parameter: print_metadata=true&page=5, - // since each page contains 100 ledgers, page=5 should print ledger ids, with metadata for(400--430) - HashMap params3 = Maps.newHashMap(); - params3.put("print_metadata", "true"); - params3.put("page", "5"); - - HttpServiceRequest request3 = new HttpServiceRequest(null, HttpServer.Method.GET, params3); - HttpServiceResponse response3 = listLedgerService.handle(request3); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - // get response, expected get 4 ledgers, and with metadata - @SuppressWarnings("unchecked") - LinkedHashMap respBody3 = JsonUtil.fromJson(response3.getBody(), LinkedHashMap.class); - assertEquals(31, respBody3.size()); - for (int i = 400; i < 430; i++) { - assertEquals(true, respBody3.containsKey(Long.valueOf(lh[i].getId()).toString())); - assertNotNull(respBody3.get(Long.valueOf(lh[i].getId()).toString())); - } - } - - /** - * Create ledgers, then test Delete Ledger service. - */ - @Test - public void testDeleteLedgerService() throws Exception { - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 4; - int numMsgs = 100; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "".getBytes()); - } - String content = "Apache BookKeeper is cool!"; - // add entries - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(content.getBytes()); - } - } - // close ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i].close(); - } - - HttpEndpointService deleteLedgerService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.DELETE_LEDGER); - - //1, null parameters of GET, should return NOT_FOUND - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = deleteLedgerService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, null parameters of DELETE, should return NOT_FOUND - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.DELETE, null); - HttpServiceResponse response2 = deleteLedgerService.handle(request2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response2.getStatusCode()); - - //3, delete first ledger, should return OK, and should only get 3 ledgers after delete. - HashMap params = Maps.newHashMap(); - Long ledgerId = lh[0].getId(); - params.put("ledger_id", ledgerId.toString()); - HttpServiceRequest request3 = new HttpServiceRequest(null, HttpServer.Method.DELETE, params); - HttpServiceResponse response3 = deleteLedgerService.handle(request3); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - // use list Ledger to verify left 3 ledger - HttpEndpointService listLedgerService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LIST_LEDGER); - HttpServiceRequest request4 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response4 = listLedgerService.handle(request4); - assertEquals(HttpServer.StatusCode.OK.getValue(), response4.getStatusCode()); - // get response , expected get 3 ledgers - @SuppressWarnings("unchecked") - LinkedHashMap respBody = JsonUtil.fromJson(response4.getBody(), LinkedHashMap.class); - assertEquals(3, respBody.size()); - } - - @Test - public void testGetLedgerMetaService() throws Exception { - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 4; - int numMsgs = 100; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "password".getBytes()); - } - String content = "Apache BookKeeper is cool!"; - // add entries - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(content.getBytes()); - } - } - // close ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i].close(); - } - HttpEndpointService getLedgerMetaService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.GET_LEDGER_META); - - //1, null parameters of GET, should return NOT_FOUND - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = getLedgerMetaService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, parameters for GET first ledger, should return OK, and contains metadata - HashMap params = Maps.newHashMap(); - Long ledgerId = lh[0].getId(); - params.put("ledger_id", ledgerId.toString()); - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, params); - HttpServiceResponse response2 = getLedgerMetaService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - @SuppressWarnings("unchecked") - HashMap respBody = JsonUtil.fromJson(response2.getBody(), HashMap.class); - assertEquals(1, respBody.size()); - @SuppressWarnings("unchecked") - HashMap expected = JsonUtil.fromJson(JsonUtil.toJson(lh[0].getLedgerMetadata()), HashMap.class); - @SuppressWarnings("unchecked") - HashMap actual = (HashMap) respBody.get(ledgerId.toString()); - - // verify LedgerMetadata content is equal - assertTrue(Maps.difference(expected, actual).areEqual()); - } - - @Test - public void testReadLedgerEntryService() throws Exception { - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 1; - int numMsgs = 100; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "".getBytes()); - } - String content = "Apache BookKeeper is cool!"; - // add entries - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(content.getBytes()); - } - } - // close ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i].close(); - } - HttpEndpointService readLedgerEntryService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.READ_LEDGER_ENTRY); - - //1, null parameters of GET, should return NOT_FOUND - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = readLedgerEntryService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, parameters for GET first ledger, should return OK - // no start/end entry id, so return all the 100 entries. - HashMap params = Maps.newHashMap(); - Long ledgerId = lh[0].getId(); - params.put("ledger_id", ledgerId.toString()); - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, params); - HttpServiceResponse response2 = readLedgerEntryService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - @SuppressWarnings("unchecked") - HashMap respBody = JsonUtil.fromJson(response2.getBody(), HashMap.class); - // default return all the entries. so should have 100 entries return - assertEquals(100, respBody.size()); - - //2, parameters for GET first ledger, should return OK - // start_entry_id=1, end_entry_id=77, so return 77 entries. - HashMap params3 = Maps.newHashMap(); - params3.put("ledger_id", ledgerId.toString()); - params3.put("start_entry_id", "1"); - params3.put("end_entry_id", "77"); - HttpServiceRequest request3 = new HttpServiceRequest(null, HttpServer.Method.GET, params3); - HttpServiceResponse response3 = readLedgerEntryService.handle(request3); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - @SuppressWarnings("unchecked") - HashMap respBody3 = JsonUtil.fromJson(response3.getBody(), HashMap.class); - assertEquals(77, respBody3.size()); - // Verify the entry content that we got. - assertTrue(respBody3.get("17").equals(content)); - } - - @Test - public void testListBookieInfoService() throws Exception { - HttpEndpointService listBookieInfoService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LIST_BOOKIE_INFO); - - //1, PUT method, should return NOT_FOUND - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response1 = listBookieInfoService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, GET method, expected get 6 bookies info and the cluster total info - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response2 = listBookieInfoService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - @SuppressWarnings("unchecked") - LinkedHashMap respBody = JsonUtil.fromJson(response2.getBody(), LinkedHashMap.class); - assertEquals(numberOfBookies + 1, respBody.size()); - for (int i = 0; i < numberOfBookies; i++) { - assertEquals(true, respBody.containsKey(getBookie(i).toString())); - } - } - - @Test - public void testGetLastLogMarkService() throws Exception { - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 4; - int numMsgs = 100; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "".getBytes()); - } - String content = "Apache BookKeeper is cool!"; - // add entries - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(content.getBytes()); - } - } - // close ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i].close(); - } - - HttpEndpointService getLastLogMarkService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LAST_LOG_MARK); - - //1, null parameters of PUT, should fail - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response1 = getLastLogMarkService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, null parameters of GET, should return 1 file - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response2 = getLastLogMarkService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - @SuppressWarnings("unchecked") - HashMap respBody = JsonUtil.fromJson(response2.getBody(), HashMap.class); - assertEquals(1, respBody.size()); - } - - @Test - public void testListDiskFilesService() throws Exception { - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 4; - int numMsgs = 100; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "".getBytes()); - } - String content = "Apache BookKeeper is cool!"; - // add entries - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(content.getBytes()); - } - } - // close ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i].close(); - } - - HttpEndpointService listDiskFileService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LIST_DISK_FILE); - - //1, null parameters of GET, should return 3 kind of files: journal, entrylog and index files - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = listDiskFileService.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - @SuppressWarnings("unchecked") - HashMap respBody = JsonUtil.fromJson(response1.getBody(), HashMap.class); - assertEquals(3, respBody.size()); - - //2, parameters of GET journal file, should return journal files - HashMap params = Maps.newHashMap(); - params.put("file_type", "journal"); - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, params); - HttpServiceResponse response2 = listDiskFileService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - @SuppressWarnings("unchecked") - HashMap respBody2 = JsonUtil.fromJson(response2.getBody(), HashMap.class); - assertEquals(1, respBody2.size()); - } - - @Test - public void testRecoveryBookieService() throws Exception { - HttpEndpointService recoveryBookieService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.RECOVERY_BOOKIE); - - //1, null body of GET, should return error - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = recoveryBookieService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, null body of PUT, should return error - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response2 = recoveryBookieService.handle(request2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response2.getStatusCode()); - - //3, body with bookie_src, bookie_dest and delete_cookie of PUT, should success. - String bookieSrc = getBookie(0).toString(); - String putBody3 = "{\"bookie_src\": [ \"" + bookieSrc + "\" ]," - + "\"delete_cookie\": false }"; - HttpServiceRequest request3 = new HttpServiceRequest(putBody3, HttpServer.Method.PUT, null); - HttpServiceResponse response3 = recoveryBookieService.handle(request3); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - - //5, body with bookie_src of PUT, should success. - String putBody5 = "{\"bookie_src\": [ \"" + bookieSrc + "\" ] }"; - HttpServiceRequest request5 = new HttpServiceRequest(putBody5, HttpServer.Method.PUT, null); - HttpServiceResponse response5 = recoveryBookieService.handle(request5); - assertEquals(HttpServer.StatusCode.OK.getValue(), response5.getStatusCode()); - } - - AuditorElector auditorElector; - private Future startAuditorElector() throws Exception { - String addr = addressByIndex(0).toString(); - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setAuditorPeriodicBookieCheckInterval(1); - conf.setMetadataServiceUri("zk://" + zkUtil.getZooKeeperConnectString() + "/ledgers"); - auditorElector = new AuditorElector(addr, conf); - return auditorElector.start(); - } - - private void stopAuditorElector() throws Exception { - auditorElector.shutdown(); - } - - @Test - public void testTriggerAuditService() throws Exception { - startAuditorElector(); - - HttpEndpointService triggerAuditService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.TRIGGER_AUDIT); - - //1, GET, should return error - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = triggerAuditService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, PUT, should success. - killBookie(1); - Thread.sleep(500); - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response2 = triggerAuditService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - stopAuditorElector(); - } - - @Test - public void testWhoIsAuditorService() throws Exception { - // start the auditor elector and wait until auditor finishes election. - startAuditorElector().get(); - - HttpEndpointService whoIsAuditorService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.WHO_IS_AUDITOR); - - //1, GET, should return success - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = whoIsAuditorService.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - LOG.info(response1.getBody()); - stopAuditorElector(); - } - - @Test - public void testListUnderReplicatedLedgerService() throws Exception { - runFunctionWithLedgerManagerFactory(baseConf, mFactory -> { - try { - testListUnderReplicatedLedgerService(mFactory); - } catch (Exception e) { - LOG.info("Exception in test", e); - throw new UncheckedExecutionException(e.getMessage(), e.getCause()); - } - return null; - }); - } - - private void testListUnderReplicatedLedgerService(LedgerManagerFactory mFactory) throws Exception { - startAuditorElector(); - - HttpEndpointService listUnderReplicatedLedgerService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LIST_UNDER_REPLICATED_LEDGER); - - //1, PUT, should return error, because only support GET. - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response1 = listUnderReplicatedLedgerService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, GET, should return success. - // first put ledger into rereplicate. then use api to list ur ledger. - @Cleanup LedgerManager ledgerManager = mFactory.newLedgerManager(); - @Cleanup final LedgerUnderreplicationManager underReplicationManager = - mFactory.newLedgerUnderreplicationManager(); - - // 192.0.2.0/24 is reserved TEST-NET range - LedgerMetadataBuilder metadata = LedgerMetadataBuilder.create() - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(3) - .newEnsembleEntry(0L, Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1000).toBookieId(), - getBookie(0), - getBookie(1))); - ClientUtil.setupLedger(ledgerManager, 1L, metadata); - - // wait for up to two minutes to complete. - // if the metadata was created just before checkAllLedgers ran, then we need to wait for the timeout - long underReplicatedLedger = -1; - for (int i = 0; i < 120; i++) { - underReplicatedLedger = underReplicationManager.pollLedgerToRereplicate(); - if (underReplicatedLedger != -1) { - LOG.info("Underreplicated ledgers found, breaking out of loop"); - break; - } - Thread.sleep(1000); - } - assertTrue(underReplicatedLedger != -1); - - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response2 = listUnderReplicatedLedgerService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - stopAuditorElector(); - } - - @Test - public void testLostBookieRecoveryDelayService() throws Exception { - HttpEndpointService lostBookieRecoveryDelayService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.LOST_BOOKIE_RECOVERY_DELAY); - - //1, PUT with null, should return error, because should contains {"delay_seconds": }. - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response1 = lostBookieRecoveryDelayService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, GET, should meet exception when get delay seconds - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response2 = lostBookieRecoveryDelayService.handle(request2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response2.getStatusCode()); - - //3, PUT, with body, should success - String putBody3 = "{\"delay_seconds\": 17 }"; - HttpServiceRequest request3 = new HttpServiceRequest(putBody3, HttpServer.Method.PUT, null); - HttpServiceResponse response3 = lostBookieRecoveryDelayService.handle(request3); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - } - - @Test - public void testDecommissionService() throws Exception { - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - startAuditorElector(); - - HttpEndpointService decommissionService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.DECOMMISSION); - - //1, PUT with null, should return error, because should contains {"bookie_src": }. - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response1 = decommissionService.handle(request1); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response1.getStatusCode()); - - //2, GET, should fail for not support get - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response2 = decommissionService.handle(request2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response2.getStatusCode()); - - //3, PUT, with body, should success. - String putBody3 = "{\"bookie_src\": \"" + getBookie(1).toString() + "\"}"; - HttpServiceRequest request3 = new HttpServiceRequest(putBody3, HttpServer.Method.PUT, null); - // after bookie kill, request should success - killBookie(1); - HttpServiceResponse response3 = decommissionService.handle(request3); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - stopAuditorElector(); - } - - @Test - public void testTriggerGCService() throws Exception { - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 4; - int numMsgs = 100; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "".getBytes()); - } - String content = "Apache BookKeeper is cool!"; - // add entries - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(content.getBytes()); - } - } - // close ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i].close(); - } - HttpEndpointService triggerGCService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.GC); - - //1, GET, should return OK - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = triggerGCService.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - assertTrue(response1.getBody().contains("\"is_in_force_gc\" : \"false\"")); - - //2, PUT, should return OK - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response2 = triggerGCService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - } - - @Test - public void testGCDetailsService() throws Exception { - baseConf.setMetadataServiceUri(zkUtil.getMetadataServiceUri()); - BookKeeper.DigestType digestType = BookKeeper.DigestType.CRC32; - int numLedgers = 4; - int numMsgs = 100; - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - // create ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "".getBytes()); - } - String content = "This is test for GC details service!"; - // add entries - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(content.getBytes()); - } - } - // close ledgers - for (int i = 0; i < numLedgers; i++) { - lh[i].close(); - } - HttpEndpointService gcDetailsService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.GC_DETAILS); - - // force trigger a GC - HttpEndpointService triggerGCService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.GC); - HttpServiceRequest request0 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response0 = triggerGCService.handle(request0); - assertEquals(HttpServer.StatusCode.OK.getValue(), response0.getStatusCode()); - - //1, GET, should return OK - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = gcDetailsService.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - LOG.info("Get response: {}", response1.getBody()); - - //2, PUT, should return NOT_FOUND - HttpServiceRequest request3 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response3 = gcDetailsService.handle(request3); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response3.getStatusCode()); - } - - @Test - public void testGetBookieState() throws Exception { - HttpEndpointService bookieStateServer = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.BOOKIE_STATE); - - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = bookieStateServer.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - - BookieState bs = JsonUtil.fromJson(response1.getBody(), BookieState.class); - assertEquals(true, bs.isRunning()); - assertEquals(false, bs.isReadOnly()); - assertEquals(true, bs.isAvailableForHighPriorityWrites()); - assertEquals(false, bs.isShuttingDown()); - } - - @Test - public void testGetBookieSanity() throws Exception { - HttpEndpointService bookieStateServer = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.BOOKIE_SANITY); - - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - ServerConfiguration conf = servers.get(0).getConfiguration(); - BookieSanityService service = new BookieSanityService(conf); - HttpServiceResponse response1 = service.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - // run multiple iteration to validate any server side throttling doesn't - // fail sequential requests. - for (int i = 0; i < 3; i++) { - BookieSanity bs = JsonUtil.fromJson(response1.getBody(), BookieSanity.class); - assertEquals(true, bs.isPassed()); - assertEquals(false, bs.isReadOnly()); - } - HttpServiceResponse response2 = bookieStateServer.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - } - - @Test - public void testGetBookieIsReady() throws Exception { - HttpEndpointService bookieStateServer = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.BOOKIE_IS_READY); - - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = bookieStateServer.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - assertEquals("OK", response1.getBody()); - - // Try using POST instead of GET - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.POST, null); - HttpServiceResponse response2 = bookieStateServer.handle(request2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response2.getStatusCode()); - - // Simulate bookies shutting down - for (int i = 0; i < bookieCount(); i++) { - serverByIndex(i).getBookie().getStateManager().forceToShuttingDown(); - } - HttpServiceRequest request3 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response3 = bookieStateServer.handle(request3); - assertEquals(HttpServer.StatusCode.SERVICE_UNAVAILABLE.getValue(), response3.getStatusCode()); - } - - @Test - public void testGetBookieInfo() throws Exception { - HttpEndpointService bookieStateServer = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.BOOKIE_INFO); - - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = bookieStateServer.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - LOG.info("Get response: {}", response1.getBody()); - - BookieInfoService.BookieInfo bs = JsonUtil.fromJson(response1.getBody(), BookieInfoService.BookieInfo.class); - assertTrue(bs.getFreeSpace() > 0); - assertTrue(bs.getTotalSpace() > 0); - - // Try using POST instead of GET - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.POST, null); - HttpServiceResponse response2 = bookieStateServer.handle(request2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response2.getStatusCode()); - } - - @Test - public void testGetClusterInfo() throws Exception { - HttpEndpointService clusterInfoServer = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.CLUSTER_INFO); - - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response1 = clusterInfoServer.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - LOG.info("Get response: {}", response1.getBody()); - - ClusterInfoService.ClusterInfo info = JsonUtil.fromJson(response1.getBody(), - ClusterInfoService.ClusterInfo.class); - assertFalse(info.isAuditorElected()); - assertTrue(info.getAuditorId().length() == 0); - assertFalse(info.isClusterUnderReplicated()); - assertTrue(info.isLedgerReplicationEnabled()); - assertTrue(info.getTotalBookiesCount() > 0); - assertTrue(info.getWritableBookiesCount() > 0); - assertTrue(info.getReadonlyBookiesCount() == 0); - assertTrue(info.getUnavailableBookiesCount() == 0); - assertTrue(info.getTotalBookiesCount() == info.getWritableBookiesCount()); - - // Try using POST instead of GET - HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.POST, null); - HttpServiceResponse response2 = clusterInfoServer.handle(request2); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response2.getStatusCode()); - } - - @Test - public void testBookieReadOnlyState() throws Exception { - HttpEndpointService bookieStateServer = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.BOOKIE_STATE); - HttpEndpointService bookieReadOnlyService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.BOOKIE_STATE_READONLY); - - // responses from both endpoints should indicate the bookie is not read only - HttpServiceRequest request = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response = bookieStateServer.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - - BookieState bs = JsonUtil.fromJson(response.getBody(), BookieState.class); - assertTrue(bs.isRunning()); - assertFalse(bs.isReadOnly()); - assertTrue(bs.isAvailableForHighPriorityWrites()); - assertFalse(bs.isShuttingDown()); - - request = new HttpServiceRequest(null, HttpServer.Method.GET, null); - response = bookieReadOnlyService.handle(request); - ReadOnlyState readOnlyState = JsonUtil.fromJson(response.getBody(), ReadOnlyState.class); - assertFalse(readOnlyState.isReadOnly()); - - // update the state to read only - request = new HttpServiceRequest(JsonUtil.toJson(new ReadOnlyState(true)), HttpServer.Method.PUT, null); - response = bookieReadOnlyService.handle(request); - readOnlyState = JsonUtil.fromJson(response.getBody(), ReadOnlyState.class); - assertTrue(readOnlyState.isReadOnly()); - - // responses from both endpoints should indicate the bookie is read only - request = new HttpServiceRequest(null, HttpServer.Method.GET, null); - response = bookieStateServer.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - - bs = JsonUtil.fromJson(response.getBody(), BookieState.class); - assertTrue(bs.isRunning()); - assertTrue(bs.isReadOnly()); - assertTrue(bs.isAvailableForHighPriorityWrites()); - assertFalse(bs.isShuttingDown()); - - request = new HttpServiceRequest(null, HttpServer.Method.GET, null); - response = bookieReadOnlyService.handle(request); - readOnlyState = JsonUtil.fromJson(response.getBody(), ReadOnlyState.class); - assertTrue(readOnlyState.isReadOnly()); - - // should be able to update the state to writable again - request = new HttpServiceRequest(JsonUtil.toJson(new ReadOnlyState(false)), HttpServer.Method.PUT, null); - response = bookieReadOnlyService.handle(request); - readOnlyState = JsonUtil.fromJson(response.getBody(), ReadOnlyState.class); - assertFalse(readOnlyState.isReadOnly()); - - // responses from both endpoints should indicate the bookie is writable - request = new HttpServiceRequest(null, HttpServer.Method.GET, null); - response = bookieStateServer.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - - bs = JsonUtil.fromJson(response.getBody(), BookieState.class); - assertTrue(bs.isRunning()); - assertFalse(bs.isReadOnly()); - assertTrue(bs.isAvailableForHighPriorityWrites()); - assertFalse(bs.isShuttingDown()); - - request = new HttpServiceRequest(null, HttpServer.Method.GET, null); - response = bookieReadOnlyService.handle(request); - readOnlyState = JsonUtil.fromJson(response.getBody(), ReadOnlyState.class); - assertFalse(readOnlyState.isReadOnly()); - - //forceReadonly to writable - baseConf.setForceReadOnlyBookie(true); - baseConf.setReadOnlyModeEnabled(true); - restartBookies(); - request = new HttpServiceRequest(JsonUtil.toJson(new ReadOnlyState(false)), HttpServer.Method.PUT, null); - response = bookieReadOnlyService.handle(request); - assertEquals(400, response.getStatusCode()); - } - - @Test - public void testSuspendCompaction() throws Exception { - HttpEndpointService suspendCompactionService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.SUSPEND_GC_COMPACTION); - - HttpEndpointService resumeCompactionService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.RESUME_GC_COMPACTION); - - //1, PUT with null body, should return error - HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response1 = suspendCompactionService.handle(request1); - assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(), response1.getStatusCode()); - - //2, PUT with null, should return error, because should contains "suspendMajor" or "suspendMinor" - String putBody2 = "{}"; - HttpServiceRequest request2 = new HttpServiceRequest(putBody2, HttpServer.Method.PUT, null); - HttpServiceResponse response2 = suspendCompactionService.handle(request2); - assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(), response2.getStatusCode()); - - - //3, GET before suspend, should success - HttpServiceRequest request3 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response3 = suspendCompactionService.handle(request3); - assertEquals(HttpServer.StatusCode.OK.getValue(), response3.getStatusCode()); - - Map responseMap = JsonUtil.fromJson( - response3.getBody(), - Map.class - ); - assertEquals(responseMap.get("isMajorGcSuspended"), "false"); - assertEquals(responseMap.get("isMinorGcSuspended"), "false"); - - - //2, PUT, with body, should success - String putBody4 = "{\"suspendMajor\": true, \"suspendMinor\": true}"; - HttpServiceRequest request4 = new HttpServiceRequest(putBody4, HttpServer.Method.PUT, null); - HttpServiceResponse response4 = suspendCompactionService.handle(request4); - assertEquals(HttpServer.StatusCode.OK.getValue(), response4.getStatusCode()); - - //3, GET after suspend, should success - HttpServiceRequest request5 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response5 = suspendCompactionService.handle(request5); - assertEquals(HttpServer.StatusCode.OK.getValue(), response5.getStatusCode()); - - Map responseMap5 = JsonUtil.fromJson( - response5.getBody(), - Map.class - ); - assertEquals(responseMap5.get("isMajorGcSuspended"), "true"); - assertEquals(responseMap5.get("isMinorGcSuspended"), "true"); - - - //2, PUT, with body, should success - String putBody6 = "{\"resumeMajor\": true, \"resumeMinor\": true}"; - HttpServiceRequest request6 = new HttpServiceRequest(putBody6, HttpServer.Method.PUT, null); - HttpServiceResponse response6 = resumeCompactionService.handle(request6); - assertEquals(HttpServer.StatusCode.OK.getValue(), response6.getStatusCode()); - - //3, GET after suspend, should success - HttpServiceRequest request7 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response7 = suspendCompactionService.handle(request7); - assertEquals(HttpServer.StatusCode.OK.getValue(), response7.getStatusCode()); - - Map responseMap7 = JsonUtil.fromJson( - response7.getBody(), - Map.class - ); - assertEquals(responseMap7.get("isMajorGcSuspended"), "false"); - assertEquals(responseMap7.get("isMinorGcSuspended"), "false"); - } - - @Test - public void testTriggerEntryLocationCompactService() throws Exception { - BookieServer bookieServer = serverByIndex(numberOfBookies - 1); - LedgerStorage spyLedgerStorage = spy(bookieServer.getBookie().getLedgerStorage()); - List dbLocationPath = Lists.newArrayList("/data1/bookkeeper/ledgers/current/locations", - "/data2/bookkeeper/ledgers/current/locations"); - when(spyLedgerStorage.getEntryLocationDBPath()) - .thenReturn(dbLocationPath); - - HashMap statusMap = Maps.newHashMap(); - statusMap.put("/data1/bookkeeper/ledgers/current/locations", false); - statusMap.put("/data2/bookkeeper/ledgers/current/locations", true); - when(spyLedgerStorage.isEntryLocationCompacting(dbLocationPath)) - .thenReturn(statusMap); - - Field ledgerStorageField = bookieServer.getBookie().getClass().getDeclaredField("ledgerStorage"); - ledgerStorageField.setAccessible(true); - ledgerStorageField.set(bookieServer.getBookie(), spyLedgerStorage); - - HttpEndpointService triggerEntryLocationCompactService = bkHttpServiceProvider - .provideHttpEndpointService(HttpServer.ApiType.TRIGGER_ENTRY_LOCATION_COMPACT); - - // 1. Put - // 1.1 Trigger all entry location rocksDB compact, should return OK - HttpServiceRequest request1 = new HttpServiceRequest("{\"entryLocationRocksDBCompact\":true}", - HttpServer.Method.PUT, null); - HttpServiceResponse response1 = triggerEntryLocationCompactService.handle(request1); - assertEquals(HttpServer.StatusCode.OK.getValue(), response1.getStatusCode()); - LOG.info("Get response: {}", response1.getBody()); - - // 1.2 Specified trigger entry location rocksDB compact, should return OK - String body2 = "{\"entryLocationRocksDBCompact\":true,\"entryLocations\"" - + ":\"/data1/bookkeeper/ledgers/current/locations\"}"; - HttpServiceRequest request2 = new HttpServiceRequest(body2, HttpServer.Method.PUT, null); - HttpServiceResponse response2 = triggerEntryLocationCompactService.handle(request2); - assertEquals(HttpServer.StatusCode.OK.getValue(), response2.getStatusCode()); - LOG.info("Get response: {}", response2.getBody()); - assertTrue(response2.getBody().contains("Triggered entry Location RocksDB")); - - // 1.3 Specified invalid entry location rocksDB compact, should return BAD_REQUEST - String body3 = "{\"entryLocationRocksDBCompact\":true,\"entryLocations\"" - + ":\"/invalid1/locations,/data2/bookkeeper/ledgers/current/locations\"}"; - HttpServiceRequest request3 = new HttpServiceRequest(body3, HttpServer.Method.PUT, null); - HttpServiceResponse response3 = triggerEntryLocationCompactService.handle(request3); - assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(), response3.getStatusCode()); - LOG.info("Get response: {}", response3.getBody()); - assertTrue(response3.getBody().contains("is invalid")); - - // 1.4 Some rocksDB is running compact, should return OK - String body4 = "{\"entryLocationRocksDBCompact\":true,\"entryLocations\"" - + ":\"/data1/bookkeeper/ledgers/current/locations,/data2/bookkeeper/ledgers/current/locations\"}"; - HttpServiceRequest request4 = new HttpServiceRequest(body4, HttpServer.Method.PUT, null); - HttpServiceResponse response4 = triggerEntryLocationCompactService.handle(request4); - assertEquals(HttpServer.StatusCode.OK.getValue(), response4.getStatusCode()); - LOG.info("Get response: {}", response4.getBody()); - - // 1.5 Put, empty body, should return BAD_REQUEST - HttpServiceRequest request5 = new HttpServiceRequest(null, HttpServer.Method.PUT, null); - HttpServiceResponse response5 = triggerEntryLocationCompactService.handle(request5); - assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(), response5.getStatusCode()); - LOG.info("Get response: {}", response5.getBody()); - - // 2. GET, should return OK - HttpServiceRequest request6 = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response6 = triggerEntryLocationCompactService.handle(request6); - assertEquals(HttpServer.StatusCode.OK.getValue(), response6.getStatusCode()); - assertTrue(response6.getBody().contains("\"/data2/bookkeeper/ledgers/current/locations\" : true")); - assertTrue(response6.getBody().contains("\"/data1/bookkeeper/ledgers/current/locations\" : false")); - - // 3. POST, should return NOT_FOUND - HttpServiceRequest request7 = new HttpServiceRequest(null, HttpServer.Method.POST, null); - HttpServiceResponse response7 = triggerEntryLocationCompactService.handle(request7); - assertEquals(HttpServer.StatusCode.METHOD_NOT_ALLOWED.getValue(), response7.getStatusCode()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/AutoRecoveryStatusServiceTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/AutoRecoveryStatusServiceTest.java deleted file mode 100644 index 69e851f0911..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/AutoRecoveryStatusServiceTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.server.http.service; - -import static org.junit.Assert.assertEquals; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.ImmutableMap; -import java.util.Map; -import org.apache.bookkeeper.http.HttpServer; -import org.apache.bookkeeper.http.service.HttpServiceRequest; -import org.apache.bookkeeper.http.service.HttpServiceResponse; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit tests for {@link AutoRecoveryStatusService}. - */ -public class AutoRecoveryStatusServiceTest extends BookKeeperClusterTestCase { - private final ObjectMapper mapper = new ObjectMapper(); - private AutoRecoveryStatusService autoRecoveryStatusService; - public AutoRecoveryStatusServiceTest() { - super(1); - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - autoRecoveryStatusService = new AutoRecoveryStatusService(baseConf); - } - - @Test - public void testGetStatus() throws Exception { - HttpServiceRequest request = new HttpServiceRequest(null, HttpServer.Method.GET, null); - HttpServiceResponse response = autoRecoveryStatusService.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - JsonNode json = mapper.readTree(response.getBody()); - assertEquals(Boolean.TRUE, json.get("enabled").asBoolean()); - } - - @Test - public void testEnableStatus() throws Exception { - Map params = ImmutableMap.of("enabled", "true"); - HttpServiceRequest request = new HttpServiceRequest(null, HttpServer.Method.PUT, params); - HttpServiceResponse response = autoRecoveryStatusService.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - JsonNode json = mapper.readTree(response.getBody()); - assertEquals(Boolean.TRUE, json.get("enabled").asBoolean()); - - request = new HttpServiceRequest(null, HttpServer.Method.GET, params); - response = autoRecoveryStatusService.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - json = mapper.readTree(response.getBody()); - assertEquals(Boolean.TRUE, json.get("enabled").asBoolean()); - } - - @Test - public void testDisableStatus() throws Exception { - Map params = ImmutableMap.of("enabled", "false"); - HttpServiceRequest request = new HttpServiceRequest(null, HttpServer.Method.PUT, params); - HttpServiceResponse response = autoRecoveryStatusService.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - JsonNode json = mapper.readTree(response.getBody()); - assertEquals(Boolean.FALSE, json.get("enabled").asBoolean()); - - request = new HttpServiceRequest(null, HttpServer.Method.GET, params); - response = autoRecoveryStatusService.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), response.getStatusCode()); - json = mapper.readTree(response.getBody()); - assertEquals(Boolean.FALSE, json.get("enabled").asBoolean()); - } - - @Test - public void testInvalidParams() throws Exception { - Map params = ImmutableMap.of("enable", "false"); - HttpServiceRequest request = new HttpServiceRequest(null, HttpServer.Method.PUT, params); - HttpServiceResponse response = autoRecoveryStatusService.handle(request); - assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(), response.getStatusCode()); - } - - @Test - public void testInvalidMethod() throws Exception { - HttpServiceRequest request = new HttpServiceRequest(null, HttpServer.Method.POST, null); - HttpServiceResponse response = autoRecoveryStatusService.handle(request); - assertEquals(HttpServer.StatusCode.NOT_FOUND.getValue(), response.getStatusCode()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/ListLedgerServiceTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/ListLedgerServiceTest.java deleted file mode 100644 index e1882eb0d91..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/ListLedgerServiceTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.server.http.service; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.ImmutableMap; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.apache.bookkeeper.bookie.BookieResources; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.http.HttpServer; -import org.apache.bookkeeper.http.service.HttpServiceRequest; -import org.apache.bookkeeper.http.service.HttpServiceResponse; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.StatsProvider; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.commons.lang3.RandomUtils; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit tests for {@link ListLedgerService}. - */ -public class ListLedgerServiceTest extends BookKeeperClusterTestCase { - private final ObjectMapper mapper = new ObjectMapper(); - private ListLedgerService listLedgerService; - - public ListLedgerServiceTest() { - super(1); - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - StatsProvider provider = new TestStatsProvider(); - listLedgerService = new ListLedgerService(confByIndex(0), - BookieResources.createMetadataDriver(confByIndex(0), - provider.getStatsLogger("")).getLedgerManagerFactory()); - } - - @Test - public void testEmptyList() throws Exception { - HttpServiceResponse response = listLedgerService.handle(new HttpServiceRequest()); - assertEquals(response.getStatusCode(), HttpServer.StatusCode.OK.getValue()); - JsonNode json = mapper.readTree(response.getBody()); - assertEquals(0, json.size()); - } - - @Test - public void testListLedgers() throws Exception { - int ledgerNum = RandomUtils.nextInt(1, 10); - Map ledgers = new HashMap<>(); - for (int i = 0; i < ledgerNum; i++) { - LedgerHandle ledger = bkc.createLedger(1, 1, 1, BookKeeper.DigestType.CRC32, new byte[0]); - ledgers.put(ledger.getId(), ledger.getLedgerMetadata()); - ledger.close(); - } - - HttpServiceResponse response = listLedgerService.handle(new HttpServiceRequest()); - assertEquals(response.getStatusCode(), HttpServer.StatusCode.OK.getValue()); - JsonNode json = mapper.readTree(response.getBody()); - assertEquals(ledgerNum, json.size()); - - json.fieldNames().forEachRemaining(field -> { - assertTrue(ledgers.containsKey(Long.parseLong(field))); - assertTrue(json.get(field).isNull()); - }); - } - - @Test - public void testListLedgersWithMetadata() throws Exception { - int ledgerNum = RandomUtils.nextInt(1, 10); - Map ledgers = new HashMap<>(); - for (int i = 0; i < ledgerNum; i++) { - LedgerHandle ledger = bkc.createLedger(1, 1, 1, BookKeeper.DigestType.CRC32, new byte[0]); - ledger.close(); - ledgers.put(ledger.getId(), ledger.getLedgerMetadata()); - } - - HttpServiceResponse response = listLedgerService.handle(new HttpServiceRequest(null, HttpServer.Method.GET, - ImmutableMap.of("print_metadata", "true"))); - assertEquals(response.getStatusCode(), HttpServer.StatusCode.OK.getValue()); - JsonNode json = mapper.readTree(response.getBody()); - assertEquals(ledgerNum, json.size()); - - json.fieldNames().forEachRemaining(field -> { - LedgerMetadata meta = ledgers.get(Long.parseLong(field)); - assertNotNull(meta); - assertFalse(json.get(field).isNull()); - }); - } - - @Test - public void testListLedgersWithMetadataDecoded() throws Exception { - int ledgerNum = RandomUtils.nextInt(1, 10); - Map ledgers = new HashMap<>(); - for (int i = 0; i < ledgerNum; i++) { - LedgerHandle ledger = bkc.createLedger(1, 1, 1, BookKeeper.DigestType.CRC32, new byte[0], - ImmutableMap.of("test_key", "test_value".getBytes())); - ledger.close(); - ledgers.put(ledger.getId(), ledger.getLedgerMetadata()); - } - - HttpServiceResponse response = listLedgerService.handle(new HttpServiceRequest(null, HttpServer.Method.GET, - ImmutableMap.of("print_metadata", "true", "decode_meta", "true"))); - assertEquals(response.getStatusCode(), HttpServer.StatusCode.OK.getValue()); - JsonNode json = mapper.readTree(response.getBody()); - assertEquals(ledgerNum, json.size()); - - json.fieldNames().forEachRemaining(field -> { - LedgerMetadata meta = ledgers.get(Long.parseLong(field)); - assertNotNull(meta); - JsonNode node = json.get(field); - assertEquals(meta.getMetadataFormatVersion(), node.get("metadataFormatVersion").asInt()); - assertEquals(meta.getEnsembleSize(), node.get("ensembleSize").asInt()); - assertEquals(meta.getWriteQuorumSize(), node.get("writeQuorumSize").asInt()); - assertEquals(meta.getAckQuorumSize(), node.get("ackQuorumSize").asInt()); - assertEquals(meta.getCToken(), node.get("ctoken").asLong()); -// assertEquals(meta.getCtime(), node.get("ctime").asLong()); - assertEquals(meta.getState().name(), node.get("state").asText()); - assertEquals(meta.isClosed(), node.get("closed").asBoolean()); - assertEquals(meta.getLength(), node.get("length").asLong()); - assertEquals(meta.getLastEntryId(), node.get("lastEntryId").asLong()); - assertEquals(meta.getDigestType().name(), node.get("digestType").asText()); - assertEquals(new String(meta.getPassword()), node.get("password").asText()); - - for (Map.Entry entry : meta.getCustomMetadata().entrySet()) { - JsonNode data = node.get("customMetadata").get(entry.getKey()); - assertArrayEquals(entry.getValue(), Base64.getDecoder().decode(data.asText())); - } - - for (Map.Entry> entry : meta.getAllEnsembles().entrySet()) { - JsonNode members = node.get("allEnsembles") - .get(String.valueOf(entry.getKey())); - assertEquals(1, entry.getValue().size()); - assertEquals(entry.getValue().size(), members.size()); - JsonNode member = members.get(0); - assertEquals(entry.getValue().get(0).getId(), member.get("id").asText()); - } - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/MetricsServiceTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/MetricsServiceTest.java deleted file mode 100644 index c46dfe29976..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/MetricsServiceTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.server.http.service; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; - -import java.io.IOException; -import java.io.Writer; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.http.HttpServer.Method; -import org.apache.bookkeeper.http.HttpServer.StatusCode; -import org.apache.bookkeeper.http.service.HttpServiceRequest; -import org.apache.bookkeeper.http.service.HttpServiceResponse; -import org.apache.bookkeeper.stats.StatsProvider; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link MetricsService}. - */ -public class MetricsServiceTest { - - private StatsProvider mockStatsProvider; - private MetricsService service; - - @Before - public void setup() { - this.mockStatsProvider = mock(StatsProvider.class); - this.service = new MetricsService(new ServerConfiguration(), mockStatsProvider); - } - - @Test - public void testForbiddenMethods() throws Exception { - HttpServiceRequest request = new HttpServiceRequest().setMethod(Method.PUT); - HttpServiceResponse response = service.handle(request); - assertEquals(StatusCode.FORBIDDEN.getValue(), response.getStatusCode()); - assertNull(response.getContentType()); - assertEquals( - "PUT is forbidden. Should be GET method", - response.getBody()); - } - - @Test - public void testNullStatsProvider() throws Exception { - service = new MetricsService(new ServerConfiguration(), null); - HttpServiceRequest request = new HttpServiceRequest().setMethod(Method.GET); - HttpServiceResponse response = service.handle(request); - assertEquals(StatusCode.INTERNAL_ERROR.getValue(), response.getStatusCode()); - assertNull(response.getContentType()); - assertEquals( - "Stats provider is not enabled. Please enable it by set statsProviderClass" - + " on bookie configuration", - response.getBody()); - } - - @Test - public void testWriteMetrics() throws Exception { - String content = "test-metrics"; - - doAnswer(invocationOnMock -> { - Writer writer = invocationOnMock.getArgument(0); - writer.write(content); - return null; - }).when(mockStatsProvider).writeAllMetrics(any(Writer.class)); - - HttpServiceRequest request = new HttpServiceRequest().setMethod(Method.GET); - HttpServiceResponse response = service.handle(request); - - assertEquals(StatusCode.OK.getValue(), response.getStatusCode()); - assertEquals(MetricsService.PROMETHEUS_CONTENT_TYPE_004, response.getContentType()); - assertEquals(content, response.getBody()); - } - - @Test - public void testWriteMetricsException() throws Exception { - doThrow(new IOException("write-metrics-exception")) - .when(mockStatsProvider).writeAllMetrics(any(Writer.class)); - - HttpServiceRequest request = new HttpServiceRequest().setMethod(Method.GET); - HttpServiceResponse response = service.handle(request); - - assertEquals(StatusCode.INTERNAL_ERROR.getValue(), response.getStatusCode()); - assertNull(response.getContentType()); - assertEquals("Exceptions are thrown when exporting metrics : write-metrics-exception", - response.getBody()); - } - - @Test - public void testWriteMetricsUnimplemented() throws Exception { - mockStatsProvider = mock(StatsProvider.class, CALLS_REAL_METHODS); - service = new MetricsService(new ServerConfiguration(), mockStatsProvider); - - HttpServiceRequest request = new HttpServiceRequest().setMethod(Method.GET); - HttpServiceResponse response = service.handle(request); - - assertEquals(StatusCode.INTERNAL_ERROR.getValue(), response.getStatusCode()); - assertNull(response.getContentType()); - assertEquals("Currently stats provider doesn't support exporting metrics in http service", - response.getBody()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/TriggerGCServiceTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/TriggerGCServiceTest.java deleted file mode 100644 index dca0466e563..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/TriggerGCServiceTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.server.http.service; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.http.HttpServer; -import org.apache.bookkeeper.http.service.HttpServiceRequest; -import org.apache.bookkeeper.http.service.HttpServiceResponse; -import org.apache.bookkeeper.proto.BookieServer; -import org.junit.Before; -import org.junit.Test; - - -/** - * Unit test for {@link TriggerGCService}. - */ -@Slf4j -public class TriggerGCServiceTest { - private TriggerGCService service; - private BookieServer mockBookieServer; - private LedgerStorage mockLedgerStorage; - - @Before - public void setup() { - this.mockBookieServer = mock(BookieServer.class, RETURNS_DEEP_STUBS); - this.mockLedgerStorage = mock(DbLedgerStorage.class); - when(mockBookieServer.getBookie().getLedgerStorage()).thenReturn(mockLedgerStorage); - when(mockLedgerStorage.isInForceGC()).thenReturn(false); - when(mockLedgerStorage.isMajorGcSuspended()).thenReturn(false); - when(mockLedgerStorage.isMinorGcSuspended()).thenReturn(false); - this.service = new TriggerGCService(new ServerConfiguration(), mockBookieServer); - } - - @Test - public void testHandleRequest() throws Exception { - - // test empty put body - HttpServiceRequest request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.PUT); - HttpServiceResponse resp = service.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), resp.getStatusCode()); - assertEquals("\"Triggered GC on BookieServer: " + mockBookieServer.getBookieId() + "\"", - resp.getBody()); - - // test invalid put json body - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.PUT); - request.setBody("test"); - resp = service.handle(request); - assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(), resp.getStatusCode()); - assertEquals("Failed to handle the request, exception: Failed to deserialize Object from Json string", - resp.getBody()); - - // test forceMajor and forceMinor not set - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.PUT); - request.setBody("{\"test\":1}"); - resp = service.handle(request); - verify(mockLedgerStorage, times(1)).forceGC(eq(true), eq(true)); - assertEquals(HttpServer.StatusCode.OK.getValue(), resp.getStatusCode()); - assertEquals("\"Triggered GC on BookieServer: " + mockBookieServer.getBookieId() + "\"", - resp.getBody()); - - // test forceMajor set, but forceMinor not set - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.PUT); - request.setBody("{\"test\":1,\"forceMajor\":true}"); - resp = service.handle(request); - verify(mockLedgerStorage, times(2)).forceGC(eq(true), eq(true)); - assertEquals(HttpServer.StatusCode.OK.getValue(), resp.getStatusCode()); - assertEquals("\"Triggered GC on BookieServer: " + mockBookieServer.getBookieId() + "\"", - resp.getBody()); - - // test forceMajor set, but forceMinor not set - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.PUT); - request.setBody("{\"test\":1,\"forceMajor\":\"true\"}"); - resp = service.handle(request); - verify(mockLedgerStorage, times(3)).forceGC(eq(true), eq(true)); - assertEquals(HttpServer.StatusCode.OK.getValue(), resp.getStatusCode()); - assertEquals("\"Triggered GC on BookieServer: " + mockBookieServer.getBookieId() + "\"", - resp.getBody()); - - // test forceMajor set to false, and forMinor not set - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.PUT); - request.setBody("{\"test\":1,\"forceMajor\":false}"); - resp = service.handle(request); - verify(mockLedgerStorage, times(1)).forceGC(eq(false), eq(true)); - assertEquals(HttpServer.StatusCode.OK.getValue(), resp.getStatusCode()); - assertEquals("\"Triggered GC on BookieServer: " + mockBookieServer.getBookieId() + "\"", - resp.getBody()); - - // test forceMajor not set and forMinor set - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.PUT); - request.setBody("{\"test\":1,\"forceMinor\":true}"); - resp = service.handle(request); - verify(mockLedgerStorage, times(4)).forceGC(eq(true), eq(true)); - assertEquals(HttpServer.StatusCode.OK.getValue(), resp.getStatusCode()); - assertEquals("\"Triggered GC on BookieServer: " + mockBookieServer.getBookieId() + "\"", - resp.getBody()); - - // test get gc - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.GET); - resp = service.handle(request); - assertEquals(HttpServer.StatusCode.OK.getValue(), resp.getStatusCode()); - assertEquals("{\n \"is_in_force_gc\" : \"false\"\n}", resp.getBody()); - - // test invalid method type - request = new HttpServiceRequest(); - request.setMethod(HttpServer.Method.POST); - resp = service.handle(request); - assertEquals(HttpServer.StatusCode.METHOD_NOT_ALLOWED.getValue(), resp.getStatusCode()); - assertEquals("Not allowed method. Should be PUT to trigger GC, Or GET to get Force GC state.", - resp.getBody()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/AsyncLedgerOpsTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/AsyncLedgerOpsTest.java deleted file mode 100644 index b5b151e622a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/AsyncLedgerOpsTest.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Random; -import java.util.Set; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.CloseCallback; -import org.apache.bookkeeper.client.AsyncCallback.CreateCallback; -import org.apache.bookkeeper.client.AsyncCallback.OpenCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This test tests read and write, synchronous and asynchronous, strings and - * integers for a BookKeeper client. The test deployment uses a ZooKeeper server - * and three BookKeepers. - * - */ -public class AsyncLedgerOpsTest extends BookKeeperClusterTestCase - implements AddCallback, ReadCallback, CreateCallback, - CloseCallback, OpenCallback { - private static final Logger LOG = LoggerFactory.getLogger(AsyncLedgerOpsTest.class); - - private final DigestType digestType; - - public AsyncLedgerOpsTest() { - super(3); - this.digestType = DigestType.CRC32; - String ledgerManagerFactory = "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"; - // set ledger manager type - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - byte[] ledgerPassword = "aaa".getBytes(); - LedgerHandle lh, lh2; - long ledgerId; - Enumeration ls; - - // test related variables - int numEntriesToWrite = 20; - int maxInt = 2147483647; - Random rng; // Random Number Generator - ArrayList entries; // generated entries - ArrayList entriesSize; - - // Synchronization - SyncObj sync; - Set syncObjs; - - class SyncObj { - int counter; - boolean value; - - public SyncObj() { - counter = 0; - value = false; - } - } - - class ControlObj { - LedgerHandle lh; - - void setLh(LedgerHandle lh) { - this.lh = lh; - } - - LedgerHandle getLh() { - return lh; - } - } - - @Test - public void testAsyncCreateClose() throws IOException, BKException { - try { - - ControlObj ctx = new ControlObj(); - - synchronized (ctx) { - LOG.info("Going to create ledger asynchronously"); - bkc.asyncCreateLedger(3, 2, digestType, ledgerPassword, this, ctx); - - ctx.wait(); - } - - // bkc.initMessageDigest("SHA1"); - LedgerHandle lh = ctx.getLh(); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.asyncAddEntry(entry.array(), this, sync); - } - - // wait for all entries to be acknowledged - synchronized (sync) { - while (sync.counter < numEntriesToWrite) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + sync.counter); - } - sync.wait(); - } - } - - LOG.info("*** WRITE COMPLETE ***"); - // close ledger - synchronized (ctx) { - lh.asyncClose(this, ctx); - ctx.wait(); - } - - // *** WRITING PART COMPLETE // READ PART BEGINS *** - - // open ledger - synchronized (ctx) { - bkc.asyncOpenLedger(ledgerId, digestType, ledgerPassword, this, ctx); - ctx.wait(); - } - lh = ctx.getLh(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + lh.getLastAddConfirmed()); - } - assertTrue("Verifying number of entries written", lh.getLastAddConfirmed() == (numEntriesToWrite - 1)); - - // read entries - lh.asyncReadEntries(0, numEntriesToWrite - 1, this, sync); - - synchronized (sync) { - while (!sync.value) { - sync.wait(); - } - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** READ COMPLETE ***"); - } - - // at this point, Enumeration ls is filled with the returned - // values - int i = 0; - while (ls.hasMoreElements()) { - ByteBuffer origbb = ByteBuffer.wrap(entries.get(i)); - Integer origEntry = origbb.getInt(); - byte[] entry = ls.nextElement().getEntry(); - ByteBuffer result = ByteBuffer.wrap(entry); - Integer retrEntry = result.getInt(); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - LOG.debug("Original entry: " + origEntry); - LOG.debug("Retrieved entry: " + retrEntry); - } - assertTrue("Checking entry " + i + " for equality", origEntry.equals(retrEntry)); - assertTrue("Checking entry " + i + " for size", entry.length == entriesSize.get(i)); - i++; - } - assertTrue("Checking number of read entries", i == numEntriesToWrite); - lh.close(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Interrupted", e); - fail("InterruptedException"); - } // catch (NoSuchAlgorithmException e) { - // e.printStackTrace(); - // } - - } - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - SyncObj x = (SyncObj) ctx; - synchronized (x) { - x.counter++; - x.notify(); - } - } - - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - ls = seq; - synchronized (sync) { - sync.value = true; - sync.notify(); - } - - } - - @Override - public void createComplete(int rc, LedgerHandle lh, Object ctx) { - synchronized (ctx) { - ControlObj cobj = (ControlObj) ctx; - cobj.setLh(lh); - cobj.notify(); - } - } - - @Override - public void openComplete(int rc, LedgerHandle lh, Object ctx) { - synchronized (ctx) { - ControlObj cobj = (ControlObj) ctx; - cobj.setLh(lh); - cobj.notify(); - } - } - - @Override - public void closeComplete(int rc, LedgerHandle lh, Object ctx) { - synchronized (ctx) { - ControlObj cobj = (ControlObj) ctx; - cobj.notify(); - } - } - - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - rng = new Random(System.currentTimeMillis()); // Initialize the Random - // Number Generator - entries = new ArrayList(); // initialize the entries list - entriesSize = new ArrayList(); - sync = new SyncObj(); // initialize the synchronization data structure - } - - - - - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookKeeperClusterTestCase.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookKeeperClusterTestCase.java deleted file mode 100644 index 76b21ecea2e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookKeeperClusterTestCase.java +++ /dev/null @@ -1,976 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.test; - -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.BOOKIE_SCOPE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.LD_INDEX_SCOPE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.LD_LEDGER_SCOPE; -import static org.apache.bookkeeper.util.BookKeeperConstants.AVAILABLE_NODE; -import static org.junit.Assert.assertFalse; - -import com.google.common.base.Stopwatch; -import java.io.File; -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; -import java.util.OptionalInt; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.BookieResources; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.LegacyCookieValidation; -import org.apache.bookkeeper.bookie.MockUncleanShutdownDetection; -import org.apache.bookkeeper.bookie.ReadOnlyBookie; -import org.apache.bookkeeper.bookie.UncleanShutdownDetection; -import org.apache.bookkeeper.bookie.UncleanShutdownDetectionImpl; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.common.allocator.ByteBufAllocatorWithOomHandler; -import org.apache.bookkeeper.common.allocator.PoolingPolicy; -import org.apache.bookkeeper.conf.AbstractConfiguration; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.discover.BookieServiceInfo; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.metastore.InMemoryMetaStore; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.replication.Auditor; -import org.apache.bookkeeper.replication.AutoRecoveryMain; -import org.apache.bookkeeper.replication.ReplicationWorker; -import org.apache.bookkeeper.server.Main; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.util.DiskChecker; -import org.apache.bookkeeper.util.PortManager; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TestName; -import org.junit.rules.Timeout; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A class runs several bookie servers for testing. - */ -public abstract class BookKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(BookKeeperClusterTestCase.class); - - @Rule - public final TestName runtime = new TestName(); - - @Rule - public final Timeout globalTimeout; - - // Metadata service related variables - protected final ZooKeeperCluster zkUtil; - protected ZooKeeper zkc; - protected String metadataServiceUri; - - // BookKeeper related variables - protected final TmpDirs tmpDirs = new TmpDirs(); - protected final List servers = new LinkedList<>(); - - protected int numBookies; - protected BookKeeperTestClient bkc; - protected boolean useUUIDasBookieId = true; - - /* - * Loopback interface is set as the listening interface and allowloopback is - * set to true in this server config. So bookies in this test process would - * bind to loopback address. - */ - protected final ServerConfiguration baseConf = TestBKConfiguration.newServerConfiguration(); - protected final ClientConfiguration baseClientConf = TestBKConfiguration.newClientConfiguration(); - private final ByteBufAllocatorWithOomHandler allocator = BookieResources.createAllocator(baseConf); - - private boolean isAutoRecoveryEnabled; - - SynchronousQueue asyncExceptions = new SynchronousQueue<>(); - protected void captureThrowable(Runnable c) { - try { - c.run(); - } catch (Throwable e) { - LOG.error("Captured error: ", e); - asyncExceptions.add(e); - } - } - - public BookKeeperClusterTestCase(int numBookies) { - this(numBookies, 120); - } - - public BookKeeperClusterTestCase(int numBookies, int testTimeoutSecs) { - this(numBookies, 1, testTimeoutSecs); - } - - public BookKeeperClusterTestCase(int numBookies, int numOfZKNodes, int testTimeoutSecs) { - this.numBookies = numBookies; - this.globalTimeout = Timeout.seconds(testTimeoutSecs); - if (numOfZKNodes == 1) { - zkUtil = new ZooKeeperUtil(); - } else { - try { - zkUtil = new ZooKeeperClusterUtil(numOfZKNodes); - } catch (IOException | KeeperException | InterruptedException e) { - throw new RuntimeException(e); - } - } - } - - @Before - public void setUp() throws Exception { - setUp("/ledgers"); - } - - protected void setUp(String ledgersRootPath) throws Exception { - LOG.info("Setting up test {}", getClass()); - InMemoryMetaStore.reset(); - setMetastoreImplClass(baseConf); - setMetastoreImplClass(baseClientConf); - - Stopwatch sw = Stopwatch.createStarted(); - try { - // start zookeeper service - startZKCluster(); - // start bookkeeper service - this.metadataServiceUri = getMetadataServiceUri(ledgersRootPath); - startBKCluster(metadataServiceUri); - LOG.info("Setup testcase {} @ metadata service {} in {} ms.", - runtime.getMethodName(), metadataServiceUri, sw.elapsed(TimeUnit.MILLISECONDS)); - } catch (Exception e) { - LOG.error("Error setting up", e); - throw e; - } - } - - protected String getMetadataServiceUri(String ledgersRootPath) { - return zkUtil.getMetadataServiceUri(ledgersRootPath); - } - - @After - public void tearDown() throws Exception { - boolean failed = false; - for (Throwable e : asyncExceptions) { - LOG.error("Got async exception: ", e); - failed = true; - } - assertFalse("Async failure", failed); - Stopwatch sw = Stopwatch.createStarted(); - LOG.info("TearDown"); - Exception tearDownException = null; - // stop bookkeeper service - try { - stopBKCluster(); - } catch (Exception e) { - LOG.error("Got Exception while trying to stop BKCluster", e); - tearDownException = e; - } - // stop zookeeper service - try { - stopZKCluster(); - } catch (Exception e) { - LOG.error("Got Exception while trying to stop ZKCluster", e); - tearDownException = e; - } - // cleanup temp dirs - try { - tmpDirs.cleanup(); - } catch (Exception e) { - LOG.error("Got Exception while trying to cleanupTempDirs", e); - tearDownException = e; - } - LOG.info("Tearing down test {} in {} ms.", runtime.getMethodName(), sw.elapsed(TimeUnit.MILLISECONDS)); - if (tearDownException != null) { - throw tearDownException; - } - } - - /** - * Start zookeeper cluster. - * - * @throws Exception - */ - protected void startZKCluster() throws Exception { - zkUtil.startCluster(); - zkc = zkUtil.getZooKeeperClient(); - } - - /** - * Stop zookeeper cluster. - * - * @throws Exception - */ - protected void stopZKCluster() throws Exception { - zkUtil.killCluster(); - } - - /** - * Start cluster. Also, starts the auto recovery process for each bookie, if - * isAutoRecoveryEnabled is true. - * - * @throws Exception - */ - protected void startBKCluster(String metadataServiceUri) throws Exception { - baseConf.setMetadataServiceUri(metadataServiceUri); - baseClientConf.setMetadataServiceUri(metadataServiceUri); - baseClientConf.setAllocatorPoolingPolicy(PoolingPolicy.UnpooledHeap); - if (numBookies > 0) { - bkc = new BookKeeperTestClient(baseClientConf, new TestStatsProvider()); - } - - // Create Bookie Servers (B1, B2, B3) - for (int i = 0; i < numBookies; i++) { - startNewBookie(); - } - } - - /** - * Stop cluster. Also, stops all the auto recovery processes for the bookie - * cluster, if isAutoRecoveryEnabled is true. - * - * @throws Exception - */ - protected void stopBKCluster() throws Exception { - if (bkc != null) { - bkc.close(); - } - - stopReplicationService(); - for (ServerTester t : servers) { - t.shutdown(); - } - servers.clear(); - } - - protected ServerConfiguration newServerConfiguration() throws Exception { - File f = tmpDirs.createNew("bookie", "test"); - - int port; - if (baseConf.isEnableLocalTransport() || !baseConf.getAllowEphemeralPorts()) { - port = PortManager.nextFreePort(); - } else { - port = 0; - } - return newServerConfiguration(port, f, new File[] { f }); - } - - protected ClientConfiguration newClientConfiguration() { - return new ClientConfiguration(baseConf); - } - - protected ServerConfiguration newServerConfiguration(int port, File journalDir, File[] ledgerDirs) { - ServerConfiguration conf = new ServerConfiguration(baseConf); - conf.setBookiePort(port); - conf.setJournalDirName(journalDir.getPath()); - String[] ledgerDirNames = new String[ledgerDirs.length]; - for (int i = 0; i < ledgerDirs.length; i++) { - ledgerDirNames[i] = ledgerDirs[i].getPath(); - } - conf.setLedgerDirNames(ledgerDirNames); - conf.setEnableTaskExecutionStats(true); - conf.setAllocatorPoolingPolicy(PoolingPolicy.UnpooledHeap); - return conf; - } - - protected void stopAllBookies() throws Exception { - stopAllBookies(true); - } - - protected void stopAllBookies(boolean shutdownClient) throws Exception { - stopReplicationService(); - for (ServerTester t : servers) { - t.shutdown(); - } - servers.clear(); - if (shutdownClient && bkc != null) { - bkc.close(); - bkc = null; - } - } - - protected String newMetadataServiceUri(String ledgersRootPath) { - return zkUtil.getMetadataServiceUri(ledgersRootPath); - } - - protected String newMetadataServiceUri(String ledgersRootPath, String type) { - return zkUtil.getMetadataServiceUri(ledgersRootPath, type); - } - - /** - * Get bookie address for bookie at index. - */ - public BookieId getBookie(int index) throws Exception { - return servers.get(index).getServer().getBookieId(); - } - - protected List bookieAddresses() throws Exception { - List bookieIds = new ArrayList<>(); - for (ServerTester a : servers) { - bookieIds.add(a.getServer().getBookieId()); - } - return bookieIds; - } - - protected List bookieLedgerDirs() throws Exception { - return servers.stream() - .flatMap(t -> Arrays.stream(t.getConfiguration().getLedgerDirs())) - .collect(Collectors.toList()); - } - - protected List bookieJournalDirs() throws Exception { - return servers.stream() - .flatMap(t -> Arrays.stream(t.getConfiguration().getJournalDirs())) - .collect(Collectors.toList()); - } - - protected BookieId addressByIndex(int index) throws Exception { - return servers.get(index).getServer().getBookieId(); - } - - protected BookieServer serverByIndex(int index) throws Exception { - return servers.get(index).getServer(); - } - - protected ServerConfiguration confByIndex(int index) throws Exception { - return servers.get(index).getConfiguration(); - } - - private Optional byAddress(BookieId addr) throws UnknownHostException { - for (ServerTester s : servers) { - if (s.getServer().getBookieId().equals(addr)) { - return Optional.of(s); - } - } - return Optional.empty(); - } - - protected int indexOfServer(BookieServer b) throws Exception { - for (int i = 0; i < servers.size(); i++) { - if (servers.get(i).getServer().equals(b)) { - return i; - } - } - return -1; - } - - protected int lastBookieIndex() { - return servers.size() - 1; - } - - protected int bookieCount() { - return servers.size(); - } - - private OptionalInt indexByAddress(BookieId addr) throws UnknownHostException { - for (int i = 0; i < servers.size(); i++) { - if (addr.equals(servers.get(i).getServer().getBookieId())) { - return OptionalInt.of(i); - } - } - return OptionalInt.empty(); - } - - /** - * Get bookie configuration for bookie. - */ - public ServerConfiguration getBkConf(BookieId addr) throws Exception { - return byAddress(addr).get().getConfiguration(); - } - - /** - * Kill a bookie by its socket address. Also, stops the autorecovery process - * for the corresponding bookie server, if isAutoRecoveryEnabled is true. - * - * @param addr - * Socket Address - * @return the configuration of killed bookie - * @throws InterruptedException - */ - public ServerConfiguration killBookie(BookieId addr) throws Exception { - Optional tester = byAddress(addr); - if (tester.isPresent()) { - if (tester.get().autoRecovery != null - && tester.get().autoRecovery.getAuditor() != null - && tester.get().autoRecovery.getAuditor().isRunning()) { - LOG.warn("Killing bookie {} who is the current Auditor", addr); - } - servers.remove(tester.get()); - tester.get().shutdown(); - return tester.get().getConfiguration(); - } - return null; - } - - /** - * Set the bookie identified by its socket address to readonly. - * - * @param addr - * Socket Address - * @throws InterruptedException - */ - public void setBookieToReadOnly(BookieId addr) throws Exception { - Optional tester = byAddress(addr); - if (tester.isPresent()) { - tester.get().getServer().getBookie().getStateManager().transitionToReadOnlyMode().get(); - } - } - - /** - * Kill a bookie by index. Also, stops the respective auto recovery process - * for this bookie, if isAutoRecoveryEnabled is true. - * - * @param index - * Bookie Index - * @return the configuration of killed bookie - * @throws InterruptedException - * @throws IOException - */ - public ServerConfiguration killBookie(int index) throws Exception { - ServerTester tester = servers.remove(index); - tester.shutdown(); - return tester.getConfiguration(); - } - - /** - * Kill bookie by index and verify that it's stopped. - * - * @param index index of bookie to kill - * - * @return configuration of killed bookie - */ - public ServerConfiguration killBookieAndWaitForZK(int index) throws Exception { - ServerTester tester = servers.get(index); // IKTODO: this method is awful - ServerConfiguration ret = killBookie(index); - while (zkc.exists(ZKMetadataDriverBase.resolveZkLedgersRootPath(baseConf) + "/" + AVAILABLE_NODE + "/" - + tester.getServer().getBookieId().toString(), false) != null) { - Thread.sleep(500); - } - return ret; - } - - /** - * Sleep a bookie. - * - * @param addr - * Socket Address - * @param seconds - * Sleep seconds - * @return Count Down latch which will be counted down just after sleep begins - * @throws InterruptedException - * @throws IOException - */ - public CountDownLatch sleepBookie(BookieId addr, final int seconds) - throws Exception { - Optional tester = byAddress(addr); - if (tester.isPresent()) { - CountDownLatch latch = new CountDownLatch(1); - Thread sleeper = new Thread() { - @Override - public void run() { - try { - tester.get().getServer().suspendProcessing(); - LOG.info("bookie {} is asleep", tester.get().getAddress()); - latch.countDown(); - Thread.sleep(seconds * 1000); - tester.get().getServer().resumeProcessing(); - LOG.info("bookie {} is awake", tester.get().getAddress()); - } catch (Exception e) { - LOG.error("Error suspending bookie", e); - } - } - }; - sleeper.start(); - return latch; - } else { - throw new IOException("Bookie not found"); - } - } - - /** - * Sleep a bookie until I count down the latch. - * - * @param addr - * Socket Address - * @param l - * Latch to wait on - * @throws InterruptedException - * @throws IOException - */ - public void sleepBookie(BookieId addr, final CountDownLatch l) - throws InterruptedException, IOException { - final CountDownLatch suspendLatch = new CountDownLatch(1); - sleepBookie(addr, l, suspendLatch); - suspendLatch.await(); - } - - public void sleepBookie(BookieId addr, final CountDownLatch l, final CountDownLatch suspendLatch) - throws InterruptedException, IOException { - Optional tester = byAddress(addr); - if (tester.isPresent()) { - BookieServer bookie = tester.get().getServer(); - LOG.info("Sleep bookie {}.", addr); - Thread sleeper = new Thread() { - @Override - public void run() { - try { - bookie.suspendProcessing(); - if (null != suspendLatch) { - suspendLatch.countDown(); - } - l.await(); - bookie.resumeProcessing(); - } catch (Exception e) { - LOG.error("Error suspending bookie", e); - } - } - }; - sleeper.start(); - } else { - throw new IOException("Bookie not found"); - } - } - - /** - * Restart bookie servers. Also restarts all the respective auto recovery - * process, if isAutoRecoveryEnabled is true. - * - * @throws InterruptedException - * @throws IOException - * @throws KeeperException - * @throws BookieException - */ - public void restartBookies() - throws Exception { - restartBookies(c -> c); - } - - /** - * Restart a bookie. Also restart the respective auto recovery process, - * if isAutoRecoveryEnabled is true. - * - * @param addr - * @throws InterruptedException - * @throws IOException - * @throws KeeperException - * @throws BookieException - */ - public void restartBookie(BookieId addr) throws Exception { - OptionalInt toRemove = indexByAddress(addr); - if (toRemove.isPresent()) { - ServerConfiguration newConfig = killBookie(toRemove.getAsInt()); - Thread.sleep(1000); - startAndAddBookie(newConfig); - } else { - throw new IOException("Bookie not found"); - } - } - - public void restartBookies(Function reconfFunction) - throws Exception { - // shut down bookie server - List confs = new ArrayList<>(); - stopReplicationService(); - for (ServerTester server : servers) { - server.shutdown(); - confs.add(server.getConfiguration()); - } - servers.clear(); - Thread.sleep(1000); - // restart them to ensure we can't - for (ServerConfiguration conf : confs) { - // ensure the bookie port is loaded correctly - startAndAddBookie(reconfFunction.apply(conf)); - } - } - - /** - * Helper method to startup a new bookie server with the indicated port - * number. Also, starts the auto recovery process, if the - * isAutoRecoveryEnabled is set true. - * - * @throws IOException - */ - public int startNewBookie() - throws Exception { - return startNewBookieAndReturnAddress().getPort(); - } - - public BookieSocketAddress startNewBookieAndReturnAddress() - throws Exception { - ServerConfiguration conf = newServerConfiguration(); - LOG.info("Starting new bookie on port: {}", conf.getBookiePort()); - return startAndAddBookie(conf).getServer().getLocalAddress(); - } - - public BookieId startNewBookieAndReturnBookieId() - throws Exception { - ServerConfiguration conf = newServerConfiguration(); - LOG.info("Starting new bookie on port: {}", conf.getBookiePort()); - return startAndAddBookie(conf).getServer().getBookieId(); - } - - protected ServerTester startAndAddBookie(ServerConfiguration conf) throws Exception { - ServerTester server = startBookie(conf); - servers.add(server); - return server; - } - - protected ServerTester startAndAddBookie(ServerConfiguration conf, Bookie b) throws Exception { - ServerTester server = startBookie(conf, b); - servers.add(server); - return server; - } - /** - * Helper method to startup a bookie server using a configuration object. - * Also, starts the auto recovery process if isAutoRecoveryEnabled is true. - * - * @param conf - * Server Configuration Object - * - */ - protected ServerTester startBookie(ServerConfiguration conf) - throws Exception { - ServerTester tester = new ServerTester(conf); - - if (bkc == null) { - bkc = new BookKeeperTestClient(baseClientConf, new TestStatsProvider()); - } - - BookieId address = tester.getServer().getBookieId(); - Future waitForBookie = conf.isForceReadOnlyBookie() - ? bkc.waitForReadOnlyBookie(address) - : bkc.waitForWritableBookie(address); - - tester.getServer().start(); - - waitForBookie.get(30, TimeUnit.SECONDS); - LOG.info("New bookie '{}' has been created.", address); - - if (isAutoRecoveryEnabled()) { - tester.startAutoRecovery(); - } - return tester; - } - - /** - * Start a bookie with the given bookie instance. Also, starts the auto - * recovery for this bookie, if isAutoRecoveryEnabled is true. - */ - protected ServerTester startBookie(ServerConfiguration conf, final Bookie b) - throws Exception { - ServerTester tester = new ServerTester(conf, b); - if (bkc == null) { - bkc = new BookKeeperTestClient(baseClientConf, new TestStatsProvider()); - } - BookieId address = tester.getServer().getBookieId(); - Future waitForBookie = conf.isForceReadOnlyBookie() - ? bkc.waitForReadOnlyBookie(address) - : bkc.waitForWritableBookie(address); - - tester.getServer().start(); - - waitForBookie.get(30, TimeUnit.SECONDS); - LOG.info("New bookie '{}' has been created.", address); - - if (isAutoRecoveryEnabled()) { - tester.startAutoRecovery(); - } - return tester; - } - - public void setMetastoreImplClass(AbstractConfiguration conf) { - conf.setMetastoreImplClass(InMemoryMetaStore.class.getName()); - } - - /** - * Flags used to enable/disable the auto recovery process. If it is enabled, - * starting the bookie server will starts the auto recovery process for that - * bookie. Also, stopping bookie will stops the respective auto recovery - * process. - * - * @param isAutoRecoveryEnabled - * Value true will enable the auto recovery process. Value false - * will disable the auto recovery process - */ - public void setAutoRecoveryEnabled(boolean isAutoRecoveryEnabled) { - this.isAutoRecoveryEnabled = isAutoRecoveryEnabled; - } - - /** - * Flag used to check whether auto recovery process is enabled/disabled. By - * default the flag is false. - * - * @return true, if the auto recovery is enabled. Otherwise return false. - */ - public boolean isAutoRecoveryEnabled() { - return isAutoRecoveryEnabled; - } - - /** - * Will starts the auto recovery process for the bookie servers. One auto - * recovery process per each bookie server, if isAutoRecoveryEnabled is - * enabled. - */ - public void startReplicationService() throws Exception { - for (ServerTester t : servers) { - t.startAutoRecovery(); - } - } - - /** - * Will stops all the auto recovery processes for the bookie cluster, if - * isAutoRecoveryEnabled is true. - */ - public void stopReplicationService() throws Exception{ - for (ServerTester t : servers) { - t.stopAutoRecovery(); - } - } - - public Auditor getAuditor(int timeout, TimeUnit unit) throws Exception { - final long timeoutAt = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, unit); - while (System.nanoTime() < timeoutAt) { - for (ServerTester t : servers) { - Auditor a = t.getAuditor(); - ReplicationWorker replicationWorker = t.getReplicationWorker(); - - // found a candidate Auditor + ReplicationWorker - if (a != null && a.isRunning() - && replicationWorker != null && replicationWorker.isRunning()) { - int deathWatchInterval = t.getConfiguration().getDeathWatchInterval(); - Thread.sleep(deathWatchInterval + 1000); - } - - // double check, because in the meantime AutoRecoveryDeathWatcher may have killed the - // AutoRecovery daemon - if (a != null && a.isRunning() - && replicationWorker != null && replicationWorker.isRunning()) { - LOG.info("Found Auditor Bookie {}", t.server.getBookieId()); - return a; - } - } - Thread.sleep(100); - } - throw new Exception("No auditor found"); - } - - /** - * Check whether the InetSocketAddress was created using a hostname or an IP - * address. Represent as 'hostname/IPaddress' if the InetSocketAddress was - * created using hostname. Represent as '/IPaddress' if the - * InetSocketAddress was created using an IPaddress - * - * @param bookieId id - * @return true if the address was created using an IP address, false if the - * address was created using a hostname - */ - public boolean isCreatedFromIp(BookieId bookieId) { - BookieSocketAddress addr = bkc.getBookieAddressResolver().resolve(bookieId); - return addr.getSocketAddress().toString().startsWith("/"); - } - - public void resetBookieOpLoggers() { - servers.forEach(t -> t.getStatsProvider().clear()); - } - - public TestStatsProvider getStatsProvider(BookieId addr) throws UnknownHostException { - return byAddress(addr).get().getStatsProvider(); - } - - public TestStatsProvider getStatsProvider(int index) throws Exception { - return servers.get(index).getStatsProvider(); - } - - /** - * Class to encapsulate all the test objects. - */ - public class ServerTester { - private final ServerConfiguration conf; - private final TestStatsProvider provider; - private final Bookie bookie; - private final BookieServer server; - private final BookieSocketAddress address; - private final MetadataBookieDriver metadataDriver; - private final RegistrationManager registrationManager; - private final LedgerManagerFactory lmFactory; - private final LedgerManager ledgerManager; - private final LedgerStorage storage; - - private AutoRecoveryMain autoRecovery; - - public ServerTester(ServerConfiguration conf) throws Exception { - this.conf = conf; - provider = new TestStatsProvider(); - - StatsLogger rootStatsLogger = provider.getStatsLogger(""); - StatsLogger bookieStats = rootStatsLogger.scope(BOOKIE_SCOPE); - - metadataDriver = BookieResources.createMetadataDriver(conf, bookieStats); - registrationManager = metadataDriver.createRegistrationManager(); - lmFactory = metadataDriver.getLedgerManagerFactory(); - ledgerManager = lmFactory.newLedgerManager(); - - LegacyCookieValidation cookieValidation = new LegacyCookieValidation( - conf, registrationManager); - cookieValidation.checkCookies(Main.storageDirectoriesFromConf(conf)); - - DiskChecker diskChecker = BookieResources.createDiskChecker(conf); - LedgerDirsManager ledgerDirsManager = BookieResources.createLedgerDirsManager( - conf, diskChecker, bookieStats.scope(LD_LEDGER_SCOPE)); - LedgerDirsManager indexDirsManager = BookieResources.createIndexDirsManager( - conf, diskChecker, bookieStats.scope(LD_INDEX_SCOPE), ledgerDirsManager); - - UncleanShutdownDetection uncleanShutdownDetection = new UncleanShutdownDetectionImpl(ledgerDirsManager); - - storage = BookieResources.createLedgerStorage( - conf, ledgerManager, ledgerDirsManager, indexDirsManager, - bookieStats, allocator); - - if (conf.isForceReadOnlyBookie()) { - bookie = new ReadOnlyBookie(conf, registrationManager, storage, - diskChecker, ledgerDirsManager, indexDirsManager, - bookieStats, allocator, BookieServiceInfo.NO_INFO); - } else { - bookie = new BookieImpl(conf, registrationManager, storage, - diskChecker, ledgerDirsManager, indexDirsManager, - bookieStats, allocator, BookieServiceInfo.NO_INFO); - } - server = new BookieServer(conf, bookie, rootStatsLogger, allocator, - uncleanShutdownDetection); - address = BookieImpl.getBookieAddress(conf); - - autoRecovery = null; - } - - public ServerTester(ServerConfiguration conf, Bookie b) throws Exception { - this.conf = conf; - provider = new TestStatsProvider(); - - metadataDriver = null; - registrationManager = null; - ledgerManager = null; - lmFactory = null; - storage = null; - - bookie = b; - server = new BookieServer(conf, b, provider.getStatsLogger(""), - allocator, new MockUncleanShutdownDetection()); - address = BookieImpl.getBookieAddress(conf); - - autoRecovery = null; - } - - public void startAutoRecovery() throws Exception { - if (LOG.isDebugEnabled()) { - LOG.debug("Starting Auditor Recovery for the bookie: {}", address); - } - autoRecovery = new AutoRecoveryMain(conf); - autoRecovery.start(); - } - - public void stopAutoRecovery() { - if (autoRecovery != null) { - if (LOG.isDebugEnabled()) { - LOG.debug("Shutdown Auditor Recovery for the bookie: {}", address); - } - autoRecovery.shutdown(); - } - } - - public Auditor getAuditor() { - if (autoRecovery != null) { - return autoRecovery.getAuditor(); - } else { - return null; - } - } - - public ReplicationWorker getReplicationWorker() { - if (autoRecovery != null) { - return autoRecovery.getReplicationWorker(); - } else { - return null; - } - } - - public ServerConfiguration getConfiguration() { - return conf; - } - - public BookieServer getServer() { - return server; - } - - public TestStatsProvider getStatsProvider() { - return provider; - } - - public BookieSocketAddress getAddress() { - return address; - } - - public void shutdown() throws Exception { - server.shutdown(); - - if (ledgerManager != null) { - ledgerManager.close(); - } - if (lmFactory != null) { - lmFactory.close(); - } - if (registrationManager != null) { - registrationManager.close(); - } - if (metadataDriver != null) { - metadataDriver.close(); - } - - if (autoRecovery != null) { - if (LOG.isDebugEnabled()) { - LOG.debug("Shutdown auto recovery for bookie server: {}", address); - } - autoRecovery.shutdown(); - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java deleted file mode 100644 index 60f89159a04..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java +++ /dev/null @@ -1,748 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.ReferenceCounted; -import io.netty.util.concurrent.DefaultThreadFactory; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.bookie.MockUncleanShutdownDetection; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeperClientStats; -import org.apache.bookkeeper.client.BookieInfoReader.BookieInfo; -import org.apache.bookkeeper.client.api.WriteFlag; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieClient; -import org.apache.bookkeeper.proto.BookieClientImpl; -import org.apache.bookkeeper.proto.BookieProtocol; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GetBookieInfoCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.apache.bookkeeper.proto.BookkeeperProtocol; -import org.apache.bookkeeper.proto.DataFormats; -import org.apache.bookkeeper.proto.checksum.DigestManager; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.apache.bookkeeper.util.ByteBufList; -import org.apache.bookkeeper.util.IOUtils; -import org.awaitility.Awaitility; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Test the bookie client. - */ -public class BookieClientTest { - BookieServer bs; - File tmpDir; - public int port = 13645; - - public EventLoopGroup eventLoopGroup; - public OrderedExecutor executor; - private ScheduledExecutorService scheduler; - - @Before - public void setUp() throws Exception { - tmpDir = IOUtils.createTempDir("bookieClient", "test"); - // Since this test does not rely on the BookKeeper client needing to - // know via ZooKeeper which Bookies are available, okay, so pass in null - // for the zkServers input parameter when constructing the BookieServer. - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - conf.setGcWaitTime(1000 * 100); - conf.setBookiePort(port) - .setJournalDirName(tmpDir.getPath()) - .setLedgerDirNames(new String[] { tmpDir.getPath() }) - .setMetadataServiceUri(null); - - bs = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - bs.start(); - eventLoopGroup = new NioEventLoopGroup(); - executor = OrderedExecutor.newBuilder() - .name("BKClientOrderedSafeExecutor") - .numThreads(2) - .build(); - scheduler = Executors.newSingleThreadScheduledExecutor( - new DefaultThreadFactory("BookKeeperClientScheduler")); - } - - @After - public void tearDown() throws Exception { - scheduler.shutdown(); - bs.shutdown(); - recursiveDelete(tmpDir); - eventLoopGroup.shutdownGracefully(); - executor.shutdown(); - } - - private static void recursiveDelete(File dir) { - File[] children = dir.listFiles(); - if (children != null) { - for (File child : children) { - recursiveDelete(child); - } - } - dir.delete(); - } - - static class ResultStruct { - int rc = -123456; - ByteBuffer entry; - } - - ReadEntryCallback recb = new ReadEntryCallback() { - - public void readEntryComplete(int rc, long ledgerId, long entryId, ByteBuf bb, Object ctx) { - ResultStruct rs = (ResultStruct) ctx; - synchronized (rs) { - rs.rc = rc; - if (BKException.Code.OK == rc && bb != null) { - bb.readerIndex(24); - rs.entry = bb.nioBuffer(); - } - rs.notifyAll(); - } - } - - }; - - WriteCallback wrcb = new WriteCallback() { - public void writeComplete(int rc, long ledgerId, long entryId, BookieId addr, Object ctx) { - if (ctx != null) { - synchronized (ctx) { - if (ctx instanceof ResultStruct) { - ResultStruct rs = (ResultStruct) ctx; - rs.rc = rc; - } - ctx.notifyAll(); - } - } - } - }; - - @Test - public void testWriteGaps() throws Exception { - final Object notifyObject = new Object(); - byte[] passwd = new byte[20]; - Arrays.fill(passwd, (byte) 'a'); - BookieId addr = bs.getBookieId(); - ResultStruct arc = new ResultStruct(); - - BookieClient bc = new BookieClientImpl(new ClientConfiguration(), eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - ByteBufList bb = createByteBuffer(1, 1, 1); - bc.addEntry(addr, 1, passwd, 1, bb, wrcb, arc, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - synchronized (arc) { - arc.wait(1000); - assertEquals(0, arc.rc); - bc.readEntry(addr, 1, 1, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(0, arc.rc); - assertEquals(1, arc.entry.getInt()); - } - bb = createByteBuffer(2, 1, 2); - bc.addEntry(addr, 1, passwd, 2, bb, wrcb, null, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - bb = createByteBuffer(3, 1, 3); - bc.addEntry(addr, 1, passwd, 3, bb, wrcb, null, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - bb = createByteBuffer(5, 1, 5); - bc.addEntry(addr, 1, passwd, 5, bb, wrcb, null, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - bb = createByteBuffer(7, 1, 7); - bc.addEntry(addr, 1, passwd, 7, bb, wrcb, null, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - synchronized (notifyObject) { - bb = createByteBuffer(11, 1, 11); - bc.addEntry(addr, 1, passwd, 11, bb, wrcb, notifyObject, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - notifyObject.wait(); - } - synchronized (arc) { - bc.readEntry(addr, 1, 6, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(BKException.Code.NoSuchEntryException, arc.rc); - } - synchronized (arc) { - bc.readEntry(addr, 1, 7, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(0, arc.rc); - assertEquals(7, arc.entry.getInt(), BookieProtocol.FLAG_NONE); - } - synchronized (arc) { - bc.readEntry(addr, 1, 1, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(0, arc.rc); - assertEquals(1, arc.entry.getInt()); - } - synchronized (arc) { - bc.readEntry(addr, 1, 2, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(0, arc.rc); - assertEquals(2, arc.entry.getInt()); - } - synchronized (arc) { - bc.readEntry(addr, 1, 3, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(0, arc.rc); - assertEquals(3, arc.entry.getInt()); - } - synchronized (arc) { - bc.readEntry(addr, 1, 4, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(BKException.Code.NoSuchEntryException, arc.rc); - } - synchronized (arc) { - bc.readEntry(addr, 1, 11, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(0, arc.rc); - assertEquals(11, arc.entry.getInt()); - } - synchronized (arc) { - bc.readEntry(addr, 1, 5, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(0, arc.rc); - assertEquals(5, arc.entry.getInt()); - } - synchronized (arc) { - bc.readEntry(addr, 1, 10, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(BKException.Code.NoSuchEntryException, arc.rc); - } - synchronized (arc) { - bc.readEntry(addr, 1, 12, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(BKException.Code.NoSuchEntryException, arc.rc); - } - synchronized (arc) { - bc.readEntry(addr, 1, 13, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(BKException.Code.NoSuchEntryException, arc.rc); - } - } - - private ByteBufList createByteBuffer(int i, long lid, long eid) { - ByteBuf bb = Unpooled.buffer(4 + 24); - bb.writeLong(lid); - bb.writeLong(eid); - bb.writeLong(eid - 1); - bb.writeInt(i); - return ByteBufList.get(bb); - } - - @Test - public void testNoLedger() throws Exception { - ResultStruct arc = new ResultStruct(); - BookieId addr = bs.getBookieId(); - BookieClient bc = new BookieClientImpl(new ClientConfiguration(), eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - synchronized (arc) { - bc.readEntry(addr, 2, 13, recb, arc, BookieProtocol.FLAG_NONE); - arc.wait(1000); - assertEquals(BKException.Code.NoSuchLedgerExistsException, arc.rc); - } - } - - @Test - public void testGetBookieInfoWithLimitStatsLogging() throws IOException, InterruptedException { - testGetBookieInfo(true); - } - - @Test - public void testGetBookieInfoWithoutLimitStatsLogging() throws IOException, InterruptedException { - testGetBookieInfo(false); - } - - public void testGetBookieInfo(boolean limitStatsLogging) throws IOException, InterruptedException { - BookieId bookieId = bs.getBookieId(); - BookieSocketAddress addr = bs.getLocalAddress(); - ClientConfiguration clientConf = new ClientConfiguration(); - clientConf.setLimitStatsLogging(limitStatsLogging); - TestStatsProvider statsProvider = new TestStatsProvider(); - TestStatsLogger statsLogger = statsProvider.getStatsLogger(""); - BookieClient bc = new BookieClientImpl(clientConf, new NioEventLoopGroup(), UnpooledByteBufAllocator.DEFAULT, - executor, scheduler, statsLogger, BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - long flags = BookkeeperProtocol.GetBookieInfoRequest.Flags.FREE_DISK_SPACE_VALUE - | BookkeeperProtocol.GetBookieInfoRequest.Flags.TOTAL_DISK_CAPACITY_VALUE; - - class CallbackObj { - int rc; - long requested; - long freeDiskSpace, totalDiskCapacity; - CountDownLatch latch = new CountDownLatch(1); - - CallbackObj(long requested) { - this.requested = requested; - this.rc = 0; - this.freeDiskSpace = 0L; - this.totalDiskCapacity = 0L; - } - } - CallbackObj obj = new CallbackObj(flags); - bc.getBookieInfo(bookieId, flags, new GetBookieInfoCallback() { - @Override - public void getBookieInfoComplete(int rc, BookieInfo bInfo, Object ctx) { - CallbackObj obj = (CallbackObj) ctx; - obj.rc = rc; - if (rc == Code.OK) { - if ((obj.requested & BookkeeperProtocol.GetBookieInfoRequest.Flags.FREE_DISK_SPACE_VALUE) != 0) { - obj.freeDiskSpace = bInfo.getFreeDiskSpace(); - } - if ((obj.requested - & BookkeeperProtocol.GetBookieInfoRequest.Flags.TOTAL_DISK_CAPACITY_VALUE) != 0) { - obj.totalDiskCapacity = bInfo.getTotalDiskSpace(); - } - } - obj.latch.countDown(); - } - - }, obj); - obj.latch.await(); - System.out.println("Return code: " + obj.rc + "FreeDiskSpace: " + obj.freeDiskSpace + " TotalCapacity: " - + obj.totalDiskCapacity); - assertTrue("GetBookieInfo failed with error " + obj.rc, obj.rc == Code.OK); - assertTrue("GetBookieInfo failed with error " + obj.rc, obj.freeDiskSpace <= obj.totalDiskCapacity); - assertTrue("GetBookieInfo failed with error " + obj.rc, obj.totalDiskCapacity > 0); - - TestOpStatsLogger perChannelBookieClientScopeOfThisAddr = (TestOpStatsLogger) statsLogger - .scope(BookKeeperClientStats.CHANNEL_SCOPE) - .scopeLabel(BookKeeperClientStats.BOOKIE_LABEL, addr.toBookieId().toString()) - .getOpStatsLogger(BookKeeperClientStats.GET_BOOKIE_INFO_OP); - int expectedBookieInfoSuccessCount = (limitStatsLogging) ? 0 : 1; - assertEquals("BookieInfoSuccessCount", expectedBookieInfoSuccessCount, - perChannelBookieClientScopeOfThisAddr.getSuccessCount()); - } - - @Test - public void testBatchRead() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - BookieClient bc = new BookieClientImpl(conf, eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieId addr = bs.getBookieId(); - byte[] passwd = new byte[20]; - Arrays.fill(passwd, (byte) 'a'); - DigestManager digestManager = DigestManager.instantiate(1, passwd, - DataFormats.LedgerMetadataFormat.DigestType.CRC32C, ByteBufAllocator.DEFAULT, true); - byte[] masterKey = DigestManager.generateMasterKey(passwd); - - final int entries = 10; - int length = 0; - for (int i = 0; i < entries; i++) { - ByteBuf bb = Unpooled.buffer(4); - bb.writeInt(i); - length += 4; - ReferenceCounted content = digestManager.computeDigestAndPackageForSending(i, i - 1, length, bb, - masterKey, BookieProtocol.FLAG_NONE); - ResultStruct arc = new ResultStruct(); - bc.addEntry(addr, 1, passwd, i, content, wrcb, arc, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - Awaitility.await().untilAsserted(() -> { - assertEquals(0, arc.rc); - }); - } - AtomicReference result = new AtomicReference<>(); - AtomicInteger resCode = new AtomicInteger(); - - bc.batchReadEntries(addr, 1, 0, 5, 5 * 1024 * 1024, (rc, ledgerId, startEntryId, bufList, ctx) -> { - resCode.set(rc); - result.set(bufList); - }, null, BookieProtocol.FLAG_NONE); - - Awaitility.await().untilAsserted(() -> { - ByteBufList byteBufList = result.get(); - assertNotNull(byteBufList); - }); - assertEquals(Code.OK, resCode.get()); - ByteBufList byteBufList = result.get(); - assertEquals(5, byteBufList.size()); - for (int i = 0; i < byteBufList.size(); i++) { - ByteBuf buffer = byteBufList.getBuffer(i); - //ledgerId - assertEquals(1, buffer.readLong()); - //entryId - assertEquals(i, buffer.readLong()); - //lac - assertEquals(i - 1, buffer.readLong()); - //length - assertEquals((i + 1) * 4, buffer.readLong()); - //digest - int i1 = buffer.readInt(); - //data - ByteBuf byteBuf = buffer.readBytes(buffer.readableBytes()); - assertEquals(i, byteBuf.readInt()); - } - } - - @Test - public void testBatchedReadWittLostFourthEntry() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - BookieClient bc = new BookieClientImpl(conf, eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieId addr = bs.getBookieId(); - byte[] passwd = new byte[20]; - Arrays.fill(passwd, (byte) 'a'); - DigestManager digestManager = DigestManager.instantiate(1, passwd, - DataFormats.LedgerMetadataFormat.DigestType.CRC32C, ByteBufAllocator.DEFAULT, true); - byte[] masterKey = DigestManager.generateMasterKey(passwd); - - final int entries = 10; - int length = 0; - for (int i = 0; i < entries; i++) { - //The bookie server lost entry:3 - if (i == 3) { - continue; - } - ByteBuf bb = Unpooled.buffer(4); - bb.writeInt(i); - length += 4; - ReferenceCounted content = digestManager.computeDigestAndPackageForSending(i, i - 1, length, bb, - masterKey, BookieProtocol.FLAG_NONE); - ResultStruct arc = new ResultStruct(); - bc.addEntry(addr, 1, passwd, i, content, wrcb, arc, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - Awaitility.await().untilAsserted(() -> { - assertEquals(0, arc.rc); - }); - } - AtomicReference result = new AtomicReference<>(); - AtomicInteger resCode = new AtomicInteger(); - - bc.batchReadEntries(addr, 1, 0, 5, 5 * 1024 * 1024, (rc, ledgerId, startEntryId, bufList, ctx) -> { - resCode.set(rc); - result.set(bufList); - }, null, BookieProtocol.FLAG_NONE); - - Awaitility.await().untilAsserted(() -> { - ByteBufList byteBufList = result.get(); - assertNotNull(byteBufList); - }); - assertEquals(Code.OK, resCode.get()); - ByteBufList byteBufList = result.get(); - assertEquals(3, byteBufList.size()); - for (int i = 0; i < byteBufList.size(); i++) { - ByteBuf buffer = byteBufList.getBuffer(i); - //ledgerId - assertEquals(1, buffer.readLong()); - //entryId - assertEquals(i, buffer.readLong()); - //lac - assertEquals(i - 1, buffer.readLong()); - //length - assertEquals((i + 1) * 4, buffer.readLong()); - //digest - int i1 = buffer.readInt(); - //data - ByteBuf byteBuf = buffer.readBytes(buffer.readableBytes()); - assertEquals(i, byteBuf.readInt()); - } - } - - @Test - public void testBatchedReadWittLostFirstEntry() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - BookieClient bc = new BookieClientImpl(conf, eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieId addr = bs.getBookieId(); - byte[] passwd = new byte[20]; - Arrays.fill(passwd, (byte) 'a'); - DigestManager digestManager = DigestManager.instantiate(1, passwd, - DataFormats.LedgerMetadataFormat.DigestType.CRC32C, ByteBufAllocator.DEFAULT, true); - byte[] masterKey = DigestManager.generateMasterKey(passwd); - - final int entries = 10; - int length = 0; - for (int i = 0; i < entries; i++) { - //The bookie server lost entry:0 - if (i == 0) { - continue; - } - ByteBuf bb = Unpooled.buffer(4); - bb.writeInt(i); - length += 4; - ReferenceCounted content = digestManager.computeDigestAndPackageForSending(i, i - 1, length, bb, - masterKey, BookieProtocol.FLAG_NONE); - ResultStruct arc = new ResultStruct(); - bc.addEntry(addr, 1, passwd, i, content, wrcb, arc, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - Awaitility.await().untilAsserted(() -> { - assertEquals(0, arc.rc); - }); - } - AtomicReference result = new AtomicReference<>(); - AtomicInteger resCode = new AtomicInteger(); - - bc.batchReadEntries(addr, 1, 0, 5, 5 * 1024 * 1024, (rc, ledgerId, startEntryId, bufList, ctx) -> { - resCode.set(rc); - result.set(bufList); - }, null, BookieProtocol.FLAG_NONE); - - Awaitility.await().untilAsserted(() -> { - ByteBufList byteBufList = result.get(); - assertNotNull(byteBufList); - }); - assertEquals(Code.NoSuchEntryException, resCode.get()); - ByteBufList byteBufList = result.get(); - assertEquals(0, byteBufList.size()); - } - - //This test is for the `isSmallEntry` improvement. - @Test - public void testBatchedReadWittBigPayload() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - BookieClient bc = new BookieClientImpl(conf, eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieId addr = bs.getBookieId(); - byte[] passwd = new byte[20]; - Arrays.fill(passwd, (byte) 'a'); - DigestManager digestManager = DigestManager.instantiate(1, passwd, - DataFormats.LedgerMetadataFormat.DigestType.CRC32C, ByteBufAllocator.DEFAULT, true); - byte[] masterKey = DigestManager.generateMasterKey(passwd); - byte[] kbData = new byte[1024]; - for (int i = 0; i < 1024; i++) { - kbData[i] = (byte) i; - } - final int entries = 20; - int length = 0; - for (int i = 0; i < entries; i++) { - ByteBuf bb = Unpooled.buffer(1024); - bb.writeBytes(kbData); - length += 1024; - ReferenceCounted content = digestManager.computeDigestAndPackageForSending(i, i - 1, length, bb, - masterKey, BookieProtocol.FLAG_NONE); - ResultStruct arc = new ResultStruct(); - bc.addEntry(addr, 1, passwd, i, content, wrcb, arc, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - Awaitility.await().untilAsserted(() -> { - assertEquals(0, arc.rc); - }); - } - - AtomicReference result = new AtomicReference<>(); - AtomicInteger resCode = new AtomicInteger(); - - bc.batchReadEntries(addr, 1, 0, 20, 5 * 1024 * 1024, (rc, ledgerId, startEntryId, bufList, ctx) -> { - result.set(bufList); - resCode.set(rc); - }, null, BookieProtocol.FLAG_NONE); - Awaitility.await().untilAsserted(() -> { - ByteBufList byteBufList = result.get(); - assertNotNull(byteBufList); - }); - ByteBufList byteBufList = result.get(); - assertEquals(0, resCode.get()); - assertEquals(20, byteBufList.size()); - for (int i = 0; i < byteBufList.size(); i++) { - ByteBuf buffer = byteBufList.getBuffer(i); - //ledgerId - assertEquals(1, buffer.readLong()); - //entryId - assertEquals(i, buffer.readLong()); - //lac - assertEquals(i - 1, buffer.readLong()); - //length - assertEquals((i + 1) * 1024, buffer.readLong()); - //digest - int i1 = buffer.readInt(); - //data - ByteBuf byteBuf = buffer.readBytes(buffer.readableBytes()); - assertEquals(1024, byteBuf.readableBytes()); - byte[] bytes = ByteBufUtil.getBytes(byteBuf); - assertTrue(Arrays.equals(kbData, bytes)); - } - } - - @Test - public void testBatchedReadWithMaxSizeLimitCase1() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - BookieClient bc = new BookieClientImpl(conf, eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieId addr = bs.getBookieId(); - byte[] passwd = new byte[20]; - Arrays.fill(passwd, (byte) 'a'); - DigestManager digestManager = DigestManager.instantiate(1, passwd, - DataFormats.LedgerMetadataFormat.DigestType.CRC32C, ByteBufAllocator.DEFAULT, true); - byte[] masterKey = DigestManager.generateMasterKey(passwd); - byte[] kbData = new byte[1024]; - for (int i = 0; i < 1024; i++) { - kbData[i] = (byte) i; - } - final int entries = 20; - int length = 0; - for (int i = 0; i < entries; i++) { - ByteBuf bb = Unpooled.buffer(1024); - bb.writeBytes(kbData); - length += 1024; - ReferenceCounted content = digestManager.computeDigestAndPackageForSending(i, i - 1, length, bb, - masterKey, BookieProtocol.FLAG_NONE); - ResultStruct arc = new ResultStruct(); - bc.addEntry(addr, 1, passwd, i, content, wrcb, arc, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - Awaitility.await().untilAsserted(() -> { - assertEquals(0, arc.rc); - }); - } - - AtomicReference result = new AtomicReference<>(); - AtomicInteger resCode = new AtomicInteger(); - - // one entry size = 8(ledgerId) + 8(entryId) + 8(lac) + 8(length) + 4(digest) + payload size - int entrySize = 8 + 8 + 8 + 8 + 4 + 1024; - bc.batchReadEntries(addr, 1, 0, 20, 5 * entrySize , (rc, ledgerId, startEntryId, bufList, ctx) -> { - result.set(bufList); - resCode.set(rc); - }, null, BookieProtocol.FLAG_NONE); - Awaitility.await().untilAsserted(() -> { - ByteBufList byteBufList = result.get(); - assertNotNull(byteBufList); - }); - ByteBufList byteBufList = result.get(); - assertEquals(0, resCode.get()); - assertEquals(4, byteBufList.size()); - for (int i = 0; i < byteBufList.size(); i++) { - ByteBuf buffer = byteBufList.getBuffer(i); - //ledgerId - assertEquals(1, buffer.readLong()); - //entryId - assertEquals(i, buffer.readLong()); - //lac - assertEquals(i - 1, buffer.readLong()); - //length - assertEquals((i + 1) * 1024, buffer.readLong()); - //digest - int i1 = buffer.readInt(); - //data - ByteBuf byteBuf = buffer.readBytes(buffer.readableBytes()); - assertEquals(1024, byteBuf.readableBytes()); - byte[] bytes = ByteBufUtil.getBytes(byteBuf); - assertTrue(Arrays.equals(kbData, bytes)); - } - } - - //consider header size rather than case1. - @Test - public void testBatchedReadWithMaxSizeLimitCase2() throws Exception { - ClientConfiguration conf = new ClientConfiguration(); - conf.setUseV2WireProtocol(true); - BookieClient bc = new BookieClientImpl(conf, eventLoopGroup, - UnpooledByteBufAllocator.DEFAULT, executor, scheduler, NullStatsLogger.INSTANCE, - BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - - BookieId addr = bs.getBookieId(); - byte[] passwd = new byte[20]; - Arrays.fill(passwd, (byte) 'a'); - DigestManager digestManager = DigestManager.instantiate(1, passwd, - DataFormats.LedgerMetadataFormat.DigestType.CRC32C, ByteBufAllocator.DEFAULT, true); - byte[] masterKey = DigestManager.generateMasterKey(passwd); - byte[] kbData = new byte[1024]; - for (int i = 0; i < 1024; i++) { - kbData[i] = (byte) i; - } - final int entries = 20; - int length = 0; - for (int i = 0; i < entries; i++) { - ByteBuf bb = Unpooled.buffer(1024); - bb.writeBytes(kbData); - length += 1024; - ReferenceCounted content = digestManager.computeDigestAndPackageForSending(i, i - 1, length, bb, - masterKey, BookieProtocol.FLAG_NONE); - ResultStruct arc = new ResultStruct(); - bc.addEntry(addr, 1, passwd, i, content, wrcb, arc, BookieProtocol.FLAG_NONE, false, WriteFlag.NONE); - Awaitility.await().untilAsserted(() -> { - assertEquals(0, arc.rc); - }); - } - - AtomicReference result = new AtomicReference<>(); - AtomicInteger resCode = new AtomicInteger(); - - // one entry size = 8(ledgerId) + 8(entryId) + 8(lac) + 8(length) + 4(digest) + payload size - int entrySize = 8 + 8 + 8 + 8 + 4 + 1024; - //response header size. - int headerSize = 24 + 8 + 4; - bc.batchReadEntries(addr, 1, 0, 20, 5 * entrySize + headerSize + (5 * 4) , - (rc, ledgerId, startEntryId, bufList, ctx) -> { - result.set(bufList); - resCode.set(rc); - }, null, BookieProtocol.FLAG_NONE); - Awaitility.await().untilAsserted(() -> { - ByteBufList byteBufList = result.get(); - assertNotNull(byteBufList); - }); - ByteBufList byteBufList = result.get(); - assertEquals(0, resCode.get()); - assertEquals(5, byteBufList.size()); - for (int i = 0; i < byteBufList.size(); i++) { - ByteBuf buffer = byteBufList.getBuffer(i); - //ledgerId - assertEquals(1, buffer.readLong()); - //entryId - assertEquals(i, buffer.readLong()); - //lac - assertEquals(i - 1, buffer.readLong()); - //length - assertEquals((i + 1) * 1024, buffer.readLong()); - //digest - int i1 = buffer.readInt(); - //data - ByteBuf byteBuf = buffer.readBytes(buffer.readableBytes()); - assertEquals(1024, byteBuf.readableBytes()); - byte[] bytes = ByteBufUtil.getBytes(byteBuf); - assertTrue(Arrays.equals(kbData, bytes)); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieFailureTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieFailureTest.java deleted file mode 100644 index eea1be20907..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieFailureTest.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Random; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.proto.BookieServer; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This test tests read and write, synchronous and asynchronous, strings and - * integers for a BookKeeper client. The test deployment uses a ZooKeeper server - * and three BookKeepers. - * - */ - -public class BookieFailureTest extends BookKeeperClusterTestCase - implements AddCallback, ReadCallback { - - // Depending on the taste, select the amount of logging - // by decommenting one of the two lines below - // private static final Logger LOG = Logger.getRootLogger(); - private static final Logger LOG = LoggerFactory.getLogger(BookieFailureTest.class); - - byte[] ledgerPassword = "aaa".getBytes(); - LedgerHandle lh, lh2; - long ledgerId; - - // test related variables - int numEntriesToWrite = 200; - int maxInt = 2147483647; - Random rng; // Random Number Generator - ArrayList entries; // generated entries - ArrayList entriesSize; - private final DigestType digestType; - - class SyncObj { - int counter; - boolean value; - boolean failureOccurred; - Enumeration ls; - - public SyncObj() { - counter = 0; - value = false; - failureOccurred = false; - ls = null; - } - } - - public BookieFailureTest() { - super(4); - this.digestType = DigestType.CRC32; - String ledgerManagerFactory = "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"; - // set ledger manager - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - /** - * Tests writes and reads when a bookie fails. - * - * @throws IOException - */ - @Test - public void testAsyncBK1() throws Exception { - LOG.info("#### BK1 ####"); - auxTestReadWriteAsyncSingleClient(serverByIndex(0)); - } - - @Test - public void testAsyncBK2() throws Exception { - LOG.info("#### BK2 ####"); - auxTestReadWriteAsyncSingleClient(serverByIndex(1)); - } - - @Test - public void testAsyncBK3() throws Exception { - LOG.info("#### BK3 ####"); - auxTestReadWriteAsyncSingleClient(serverByIndex(2)); - } - - @Test - public void testAsyncBK4() throws Exception { - LOG.info("#### BK4 ####"); - auxTestReadWriteAsyncSingleClient(serverByIndex(3)); - } - - @Test - public void testBookieRecovery() throws Exception { - //Shutdown all but 1 bookie (should be in it's own test case with 1 bookie) - assertEquals(4, bookieCount()); - killBookie(0); - killBookie(0); - killBookie(0); - - byte[] passwd = "blah".getBytes(); - LedgerHandle lh = bkc.createLedger(1, 1, digestType, passwd); - - int numEntries = 100; - for (int i = 0; i < numEntries; i++) { - byte[] data = ("" + i).getBytes(); - lh.addEntry(data); - } - - assertEquals(1, bookieCount()); - restartBookies(); - - assertEquals(numEntries - 1 , lh.getLastAddConfirmed()); - Enumeration entries = lh.readEntries(0, lh.getLastAddConfirmed()); - - int numScanned = 0; - while (entries.hasMoreElements()) { - assertEquals(("" + numScanned), new String(entries.nextElement().getEntry())); - numScanned++; - } - assertEquals(numEntries, numScanned); - } - - void auxTestReadWriteAsyncSingleClient(BookieServer bs) throws IOException { - SyncObj sync = new SyncObj(); - try { - // Create a ledger - lh = bkc.createLedger(3, 2, digestType, ledgerPassword); - - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.asyncAddEntry(entry.array(), this, sync); - - } - - LOG.info("Wrote " + numEntriesToWrite + " and now going to fail bookie."); - // Bookie fail - bs.shutdown(); - - // wait for all entries to be acknowledged - synchronized (sync) { - while (sync.counter < numEntriesToWrite) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + sync.counter); - } - sync.wait(10000); - assertFalse("Failure occurred during write", sync.failureOccurred); - } - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - - // *** WRITING PART COMPLETE // READ PART BEGINS *** - - // open ledger - bkc.close(); - bkc = new BookKeeperTestClient(baseClientConf); - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + (lh.getLastAddConfirmed() + 1)); - } - assertTrue("Verifying number of entries written", lh.getLastAddConfirmed() == (numEntriesToWrite - 1)); - - // read entries - - lh.asyncReadEntries(0, numEntriesToWrite - 1, this, sync); - - synchronized (sync) { - int i = 0; - sync.wait(10000); - assertFalse("Failure occurred during read", sync.failureOccurred); - assertTrue("Haven't received entries", sync.value); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** READ COMPLETE ***"); - } - - // at this point, Enumeration ls is filled with the returned - // values - int i = 0; - while (sync.ls.hasMoreElements()) { - ByteBuffer origbb = ByteBuffer.wrap(entries.get(i)); - Integer origEntry = origbb.getInt(); - byte[] entry = sync.ls.nextElement().getEntry(); - ByteBuffer result = ByteBuffer.wrap(entry); - - Integer retrEntry = result.getInt(); - if (LOG.isDebugEnabled()) { - LOG.debug("Retrieved entry: " + i); - } - assertTrue("Checking entry " + i + " for equality", origEntry.equals(retrEntry)); - assertTrue("Checking entry " + i + " for size", entry.length == entriesSize.get(i)); - i++; - } - - assertTrue("Checking number of read entries", i == numEntriesToWrite); - - LOG.info("Verified that entries are ok, and now closing ledger"); - lh.close(); - } catch (BKException e) { - LOG.error("Caught BKException", e); - fail(e.toString()); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Caught InterruptedException", e); - fail(e.toString()); - } - - } - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - SyncObj x = (SyncObj) ctx; - if (rc != 0) { - LOG.error("Failure during add {} {}", entryId, rc); - x.failureOccurred = true; - } - synchronized (x) { - x.counter++; - x.notify(); - } - } - - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - SyncObj x = (SyncObj) ctx; - if (rc != 0) { - LOG.error("Failure during add {}", rc); - x.failureOccurred = true; - } - synchronized (x) { - x.value = true; - x.ls = seq; - x.notify(); - } - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - - rng = new Random(System.currentTimeMillis()); // Initialize the Random - // Number Generator - entries = new ArrayList(); // initialize the entries list - entriesSize = new ArrayList(); - - zkc.close(); - } - - @Test - public void testLedgerNoRecoveryOpenAfterBKCrashed() throws Exception { - // Create a ledger - LedgerHandle beforelh = bkc.createLedger(numBookies, numBookies, digestType, "".getBytes()); - - int numEntries = 10; - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < numEntries; i++) { - beforelh.addEntry(tmp.getBytes()); - } - - // shutdown first bookie server - killBookie(0); - - // try to open ledger no recovery - LedgerHandle afterlh = bkc.openLedgerNoRecovery(beforelh.getId(), digestType, "".getBytes()); - - assertEquals(numEntries - 2, afterlh.getLastAddConfirmed()); - } - - @Test - public void testLedgerOpenAfterBKCrashed() throws Exception { - // Create a ledger - LedgerHandle beforelh = bkc.createLedger(numBookies, numBookies, digestType, "".getBytes()); - - int numEntries = 10; - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < numEntries; i++) { - beforelh.addEntry(tmp.getBytes()); - } - - // shutdown first bookie server - killBookie(0); - startNewBookie(); - - // try to open ledger with recovery - LedgerHandle afterlh = bkc.openLedger(beforelh.getId(), digestType, "".getBytes()); - assertEquals(beforelh.getLastAddPushed(), afterlh.getLastAddConfirmed()); - - // try to open ledger no recovery - // bookies: 4, ensSize: 3, ackQuorumSize: 2 - LedgerHandle beforelhWithNoRecovery = bkc.createLedger(numBookies - 1 , 2, digestType, "".getBytes()); - for (int i = 0; i < numEntries; i++) { - beforelhWithNoRecovery.addEntry(tmp.getBytes()); - } - - // shutdown first bookie server - killBookie(0); - - // try to open ledger no recovery, should be able to open ledger - bkc.openLedger(beforelhWithNoRecovery.getId(), digestType, "".getBytes()); - } - - /** - * Verify read last confirmed op, it shouldn't cause any deadlock as new - * bookie connection is being established and returning the connection - * notification in the same caller thread. It would be simulated by delaying - * the future.addlistener() in PerChannelBookieClient after the connection - * establishment. Now the future.addlistener() will notify back in the same - * thread and simultaneously invoke the pendingOp.operationComplete() event. - * - *

BOOKKEEPER-326 - */ - @Test - public void testReadLastConfirmedOp() throws Exception { - startNewBookie(); - startNewBookie(); - // Create a ledger - LedgerHandle beforelh = bkc.createLedger(numBookies + 2, - numBookies + 2, digestType, "".getBytes()); - - int numEntries = 10; - String tmp = "BookKeeper is cool!"; - for (int i = 0; i < numEntries; i++) { - beforelh.addEntry(tmp.getBytes()); - } - - // shutdown first bookie server - killBookie(0); - startNewBookie(); - - // create new bookie client, and forcing to establish new - // PerChannelBookieClient connections for recovery flows. - BookKeeperTestClient bkc1 = new BookKeeperTestClient(baseClientConf); - // try to open ledger with recovery - LedgerHandle afterlh = bkc1.openLedger(beforelh.getId(), digestType, "" - .getBytes()); - - assertEquals("Entries got missed", beforelh.getLastAddPushed(), afterlh - .getLastAddConfirmed()); - bkc1.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingTest.java deleted file mode 100644 index 4b0243f672b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingTest.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.util.Enumeration; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.awaitility.Awaitility; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class tests that bookie rolling journals. - */ -public class BookieJournalRollingTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(BookieJournalRollingTest.class); - - private final DigestType digestType; - - public BookieJournalRollingTest() { - super(1); - this.digestType = DigestType.CRC32; - this.baseConf.setAllowEphemeralPorts(false); - } - - @Before - @Override - public void setUp() throws Exception { - // Set up the configuration properties needed. - baseConf.setMaxJournalSizeMB(1); - baseConf.setMaxBackupJournals(2); - super.setUp(); - } - - @After - @Override - public void tearDown() throws Exception { - super.tearDown(); - } - - /** - * Common method to create ledgers and write entries to them. - */ - protected LedgerHandle[] writeLedgerEntries(int numLedgers, int msgSize, int numMsgs) throws Exception { - // Create the ledgers - LedgerHandle[] lhs = new LedgerHandle[numLedgers]; - long[] ledgerIds = new long[numLedgers]; - for (int i = 0; i < numLedgers; i++) { - lhs[i] = bkc.createLedger(1, 1, digestType, "".getBytes()); - ledgerIds[i] = lhs[i].getId(); - } - writeLedgerEntries(lhs, msgSize, numMsgs); - // Return the ledger handles to the inserted ledgers and entries - return lhs; - } - - protected void writeLedgerEntries(LedgerHandle[] lhs, int msgSize, int numMsgs) throws Exception { - // Create a dummy message string to write as ledger entries - StringBuilder msgSB = new StringBuilder(); - for (int i = 0; i < msgSize; i++) { - msgSB.append("a"); - } - String msg = msgSB.toString(); - - final CountDownLatch completeLatch = new CountDownLatch(numMsgs * lhs.length); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - - // Write all of the entries for all of the ledgers - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < lhs.length; j++) { - StringBuilder sb = new StringBuilder(); - sb.append(lhs[j].getId()).append('-').append(i).append('-') - .append(msg); - lhs[j].asyncAddEntry(sb.toString().getBytes(), new AddCallback() { - public void addComplete(int rc2, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rc2); - completeLatch.countDown(); - } - }, null); - } - } - completeLatch.await(); - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - } - - protected void validLedgerEntries(long[] ledgerIds, int msgSize, int numMsgs) throws Exception { - // Open the ledgers - LedgerHandle[] lhs = new LedgerHandle[ledgerIds.length]; - for (int i = 0; i < lhs.length; i++) { - lhs[i] = bkc.openLedger(ledgerIds[i], digestType, "".getBytes()); - } - - StringBuilder msgSB = new StringBuilder(); - for (int i = 0; i < msgSize; i++) { - msgSB.append("a"); - } - String msg = msgSB.toString(); - - int numToRead = 10; - // read all of the entries for all the ledgers - for (int j = 0; j < lhs.length; j++) { - int start = 0; - int read = Math.min(numToRead, numMsgs - start); - int end = start + read - 1; - int entryId = 0; - if (LOG.isDebugEnabled()) { - LOG.debug("Validating Entries of Ledger " + ledgerIds[j]); - } - while (start < numMsgs) { - Enumeration seq = lhs[j].readEntries(start, end); - assertTrue("Enumeration of ledger entries has no element", seq.hasMoreElements()); - while (seq.hasMoreElements()) { - LedgerEntry e = seq.nextElement(); - assertEquals(entryId, e.getEntryId()); - - StringBuilder sb = new StringBuilder(); - sb.append(ledgerIds[j]).append('-').append(entryId).append('-') - .append(msg); - assertArrayEquals(sb.toString().getBytes(), e.getEntry()); - entryId++; - } - assertEquals(entryId - 1, end); - start = end + 1; - read = Math.min(numToRead, numMsgs - start); - end = start + read - 1; - } - } - - for (LedgerHandle lh : lhs) { - lh.close(); - } - } - - /** - * This test writes enough ledger entries to roll over the journals. - * - *

It will then keep only 1 journal file before last marked journal - * - * @throws Exception - */ - @Test - public void testJournalRolling() throws Exception { - if (LOG.isDebugEnabled()) { - LOG.debug("Testing Journal Rolling"); - } - // Write enough ledger entries so that we roll over journals - LedgerHandle[] lhs = writeLedgerEntries(4, 1024, 1024); - long[] ledgerIds = new long[lhs.length]; - for (int i = 0; i < lhs.length; i++) { - ledgerIds[i] = lhs[i].getId(); - lhs[i].close(); - } - - Awaitility.await().untilAsserted(() -> { - // verify that we only keep at most journal files - for (File journalDir : bookieJournalDirs()) { - File[] journals = journalDir.listFiles(); - int numJournals = 0; - for (File f : journals) { - if (!f.getName().endsWith(".txn")) { - continue; - } - ++numJournals; - } - assertTrue(numJournals <= 2); - } - } - ); - - // restart bookies - // ensure after restart we can read the entries since journals rolls - restartBookies(); - validLedgerEntries(ledgerIds, 1024, 1024); - } - - /** - * This test writes enough ledger entries to roll over the journals - * without sync up. - * - * @throws Exception - */ - @Test - public void testJournalRollingWithoutSyncup() throws Exception { - if (LOG.isDebugEnabled()) { - LOG.debug("Testing Journal Rolling without sync up"); - } - - // set flush interval to a large value - // restart bookies - restartBookies(c -> { - c.setFlushInterval(999999999); - c.setAllowEphemeralPorts(false); - return c; - }); - - // Write enough ledger entries so that we roll over journals - LedgerHandle[] lhs = writeLedgerEntries(4, 1024, 1024); - long[] ledgerIds = new long[lhs.length]; - for (int i = 0; i < lhs.length; i++) { - ledgerIds[i] = lhs[i].getId(); - lhs[i].close(); - } - - // ledger indexes are not flushed - // and after bookies restarted, journals will be relayed - // ensure that we can still read the entries - restartBookies(); - validLedgerEntries(ledgerIds, 1024, 1024); - } - - /** - * This test writes enough ledger entries to roll over the journals - * without sync up. - * - * @throws Exception - */ - @Test - public void testReplayDeletedLedgerJournalEntries() throws Exception { - if (LOG.isDebugEnabled()) { - LOG.debug("Testing replaying journal entries whose ledger has been removed."); - } - - // Write entries - LedgerHandle[] lhs = writeLedgerEntries(1, 1024, 10); - // Wait until all entries are flushed and last mark rolls - Thread.sleep(3 * baseConf.getFlushInterval()); - - // restart bookies with flush interval set to a large value - // restart bookies - restartBookies(c -> { - c.setFlushInterval(999999999); - c.setAllowEphemeralPorts(false); - return c; - }); - - // Write entries again to let them existed in journal - writeLedgerEntries(lhs, 1024, 10); - - // delete them - for (LedgerHandle lh : lhs) { - bkc.deleteLedger(lh.getId()); - } - // wait for gc - Thread.sleep(2 * confByIndex(0).getGcWaitTime()); - - // restart bookies again to trigger replaying journal - restartBookies(); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingWithReuseJournalTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingWithReuseJournalTest.java deleted file mode 100644 index 7a60e9f23cd..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingWithReuseJournalTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.LedgerHandle; -import org.awaitility.Awaitility; -import org.junit.Before; -import org.junit.Test; - -/** - * This class tests that bookie rolling journals for reuse journal files. - */ -@Slf4j -public class BookieJournalRollingWithReuseJournalTest extends BookieJournalRollingTest { - - public BookieJournalRollingWithReuseJournalTest() { - super(); - } - - @Before - @Override - public void setUp() throws Exception { - baseConf.setJournalReuseFiles(true); - super.setUp(); - } - - @Test - public void testJournalRolling() throws Exception { - if (log.isDebugEnabled()) { - log.debug("Testing Journal Rolling"); - } - - // Write enough ledger entries so that we roll over journals - LedgerHandle[] lhs = writeLedgerEntries(10, 1024, 1024); - long[] ledgerIds = new long[lhs.length]; - for (int i = 0; i < lhs.length; i++) { - ledgerIds[i] = lhs[i].getId(); - lhs[i].close(); - } - - Awaitility.await().untilAsserted(() -> { - // verify that we only keep at most journal files - for (File journalDir : bookieJournalDirs()) { - File[] journals = journalDir.listFiles(); - int numJournals = 0; - for (File f : journals) { - if (!f.getName().endsWith(".txn")) { - continue; - } - ++numJournals; - } - assertTrue(numJournals <= 2); - } - }); - - // restart bookies - // ensure after restart we can read the entries since journals rolls - restartBookies(); - validLedgerEntries(ledgerIds, 1024, 1024); - } - -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieReadWriteTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieReadWriteTest.java deleted file mode 100644 index 870943b7a93..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieReadWriteTest.java +++ /dev/null @@ -1,1342 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.CloseCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadLastConfirmedCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.BKIllegalOpException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.streaming.LedgerInputStream; -import org.apache.bookkeeper.streaming.LedgerOutputStream; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This test tests read and write, synchronous and asynchronous, strings and - * integers for a BookKeeper client. The test deployment uses a ZooKeeper server - * and three BookKeepers. - * - */ -public class BookieReadWriteTest extends BookKeeperClusterTestCase - implements AddCallback, ReadCallback, ReadLastConfirmedCallback { - - // Depending on the taste, select the amount of logging - // by decommenting one of the two lines below - // private static final Logger LOG = Logger.getRootLogger(); - private static final Logger LOG = LoggerFactory.getLogger(BookieReadWriteTest.class); - - byte[] ledgerPassword = "aaa".getBytes(); - LedgerHandle lh, lh2; - long ledgerId; - - // test related variables - int numEntriesToWrite = 200; - int maxInt = 2147483647; - Random rng; // Random Number Generator - ArrayList entries; // generated entries - ArrayList entriesSize; - - private final DigestType digestType; - - public BookieReadWriteTest() { - super(3); - this.digestType = DigestType.CRC32; - String ledgerManagerFactory = "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"; - // set ledger manager - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - class SyncObj { - long lastConfirmed; - volatile int counter; - boolean value; - AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - Enumeration ls = null; - - public SyncObj() { - counter = 0; - lastConfirmed = LedgerHandle.INVALID_ENTRY_ID; - value = false; - } - - void setReturnCode(int rc) { - this.rc.compareAndSet(BKException.Code.OK, rc); - } - - int getReturnCode() { - return rc.get(); - } - - void setLedgerEntries(Enumeration ls) { - this.ls = ls; - } - - Enumeration getLedgerEntries() { - return ls; - } - } - - @Test - public void testOpenException() throws IOException, InterruptedException { - try { - lh = bkc.openLedger(0, digestType, ledgerPassword); - fail("Haven't thrown exception"); - } catch (BKException e) { - LOG.warn("Successfully thrown and caught exception:", e); - } - } - - /** - * test the streaming api for reading and writing. - * - * @throws IOException - */ - @Test - public void testStreamingClients() throws IOException, BKException, InterruptedException { - lh = bkc.createLedger(digestType, ledgerPassword); - // write a string so that we cna - // create a buffer of a single bytes - // and check for corner cases - String toWrite = "we need to check for this string to match " + "and for the record mahadev is the best"; - LedgerOutputStream lout = new LedgerOutputStream(lh, 1); - byte[] b = toWrite.getBytes(); - lout.write(b); - lout.close(); - long lId = lh.getId(); - lh.close(); - // check for sanity - lh = bkc.openLedger(lId, digestType, ledgerPassword); - LedgerInputStream lin = new LedgerInputStream(lh, 1); - byte[] bread = new byte[b.length]; - int read = 0; - while (read < b.length) { - read = read + lin.read(bread, read, b.length); - } - - String newString = new String(bread); - assertTrue("these two should same", toWrite.equals(newString)); - lin.close(); - lh.close(); - // create another ledger to write one byte at a time - lh = bkc.createLedger(digestType, ledgerPassword); - lout = new LedgerOutputStream(lh); - for (int i = 0; i < b.length; i++) { - lout.write(b[i]); - } - lout.close(); - lId = lh.getId(); - lh.close(); - lh = bkc.openLedger(lId, digestType, ledgerPassword); - lin = new LedgerInputStream(lh); - bread = new byte[b.length]; - read = 0; - while (read < b.length) { - read = read + lin.read(bread, read, b.length); - } - newString = new String(bread); - assertTrue("these two should be same ", toWrite.equals(newString)); - lin.close(); - lh.close(); - } - - private void testReadWriteAsyncSingleClient(int numEntries) throws IOException { - SyncObj sync = new SyncObj(); - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.asyncAddEntry(entry.array(), this, sync); - } - - // wait for all entries to be acknowledged - synchronized (sync) { - while (sync.counter < numEntriesToWrite) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + sync.counter); - } - sync.wait(); - } - assertEquals("Error adding", BKException.Code.OK, sync.getReturnCode()); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - - // *** WRITING PART COMPLETE // READ PART BEGINS *** - - // open ledger - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + (lh.getLastAddConfirmed() + 1)); - } - assertTrue("Verifying number of entries written", lh.getLastAddConfirmed() == (numEntriesToWrite - 1)); - - // read entries - lh.asyncReadEntries(0, numEntriesToWrite - 1, this, sync); - - synchronized (sync) { - while (!sync.value) { - sync.wait(); - } - assertEquals("Error reading", BKException.Code.OK, sync.getReturnCode()); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** READ COMPLETE ***"); - } - - // at this point, Enumeration ls is filled with the returned - // values - int i = 0; - Enumeration ls = sync.getLedgerEntries(); - while (ls.hasMoreElements()) { - ByteBuffer origbb = ByteBuffer.wrap(entries.get(i)); - Integer origEntry = origbb.getInt(); - byte[] entry = ls.nextElement().getEntry(); - ByteBuffer result = ByteBuffer.wrap(entry); - Integer retrEntry = result.getInt(); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - LOG.debug("Original entry: " + origEntry); - LOG.debug("Retrieved entry: " + retrEntry); - } - assertTrue("Checking entry " + i + " for equality", origEntry.equals(retrEntry)); - assertTrue("Checking entry " + i + " for size", entry.length == entriesSize.get(i)); - i++; - } - assertTrue("Checking number of read entries", i == numEntriesToWrite); - - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testReadWriteAsyncSingleClient200() throws IOException { - testReadWriteAsyncSingleClient(200); - } - - /** - * Check that the add api with offset and length work correctly. - * First try varying the offset. Then the length with a fixed non-zero - * offset. - */ - @Test - public void testReadWriteRangeAsyncSingleClient() throws IOException { - SyncObj sync = new SyncObj(); - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - byte[] bytes = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'}; - - lh.asyncAddEntry(bytes, 0, bytes.length, this, sync); - lh.asyncAddEntry(bytes, 0, 4, this, sync); // abcd - lh.asyncAddEntry(bytes, 3, 4, this, sync); // defg - lh.asyncAddEntry(bytes, 3, (bytes.length - 3), this, sync); // defghi - int numEntries = 4; - - // wait for all entries to be acknowledged - synchronized (sync) { - while (sync.counter < numEntries) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + sync.counter); - } - sync.wait(); - } - assertEquals("Error adding", BKException.Code.OK, sync.getReturnCode()); - } - - try { - lh.asyncAddEntry(bytes, -1, bytes.length, this, sync); - fail("Shouldn't be able to use negative offset"); - } catch (ArrayIndexOutOfBoundsException aiob) { - // expected - } - try { - lh.asyncAddEntry(bytes, 0, bytes.length + 1, this, sync); - fail("Shouldn't be able to use that much length"); - } catch (ArrayIndexOutOfBoundsException aiob) { - // expected - } - try { - lh.asyncAddEntry(bytes, -1, bytes.length + 2, this, sync); - fail("Shouldn't be able to use negative offset " - + "with that much length"); - } catch (ArrayIndexOutOfBoundsException aiob) { - // expected - } - try { - lh.asyncAddEntry(bytes, 4, -3, this, sync); - fail("Shouldn't be able to use negative length"); - } catch (ArrayIndexOutOfBoundsException aiob) { - // expected - } - try { - lh.asyncAddEntry(bytes, -4, -3, this, sync); - fail("Shouldn't be able to use negative offset & length"); - } catch (ArrayIndexOutOfBoundsException aiob) { - // expected - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - - // *** WRITING PART COMPLETE // READ PART BEGINS *** - - // open ledger - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + (lh.getLastAddConfirmed() + 1)); - } - assertTrue("Verifying number of entries written", - lh.getLastAddConfirmed() == (numEntries - 1)); - - // read entries - lh.asyncReadEntries(0, numEntries - 1, this, sync); - - synchronized (sync) { - while (!sync.value) { - sync.wait(); - } - assertEquals("Error reading", BKException.Code.OK, sync.getReturnCode()); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** READ COMPLETE ***"); - } - - // at this point, Enumeration ls is filled with the returned - // values - int i = 0; - Enumeration ls = sync.getLedgerEntries(); - while (ls.hasMoreElements()) { - byte[] expected = null; - byte[] entry = ls.nextElement().getEntry(); - - switch (i) { - case 0: - expected = Arrays.copyOfRange(bytes, 0, bytes.length); - break; - case 1: - expected = Arrays.copyOfRange(bytes, 0, 4); - break; - case 2: - expected = Arrays.copyOfRange(bytes, 3, 3 + 4); - break; - case 3: - expected = Arrays.copyOfRange(bytes, 3, 3 + (bytes.length - 3)); - break; - } - assertNotNull("There are more checks than writes", expected); - - String message = "Checking entry " + i + " for equality [" - + new String(entry, "UTF-8") + "," - + new String(expected, "UTF-8") + "]"; - assertTrue(message, Arrays.equals(entry, expected)); - - i++; - } - assertTrue("Checking number of read entries", i == numEntries); - - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - class ThrottleTestCallback implements ReadCallback { - int throttle; - - ThrottleTestCallback(int threshold) { - this.throttle = threshold; - } - - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - SyncObj sync = (SyncObj) ctx; - sync.setLedgerEntries(seq); - sync.setReturnCode(rc); - synchronized (sync) { - sync.counter += throttle; - sync.notify(); - } - LOG.info("Current counter: " + sync.counter); - } - } - - @Test - public void testSyncReadAsyncWriteStringsSingleClient() throws IOException { - SyncObj sync = new SyncObj(); - LOG.info("TEST READ WRITE STRINGS MIXED SINGLE CLIENT"); - String charset = "utf-8"; - if (LOG.isDebugEnabled()) { - LOG.debug("Default charset: " + Charset.defaultCharset()); - } - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - int randomInt = rng.nextInt(maxInt); - byte[] entry = Integer.toString(randomInt).getBytes(charset); - entries.add(entry); - lh.asyncAddEntry(entry, this, sync); - } - - // wait for all entries to be acknowledged - synchronized (sync) { - while (sync.counter < numEntriesToWrite) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + sync.counter); - } - sync.wait(); - } - assertEquals("Error adding", BKException.Code.OK, sync.getReturnCode()); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("*** ASYNC WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - - // *** WRITING PART COMPLETED // READ PART BEGINS *** - - // open ledger - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + (lh.getLastAddConfirmed() + 1)); - } - assertTrue("Verifying number of entries written", lh.getLastAddConfirmed() == (numEntriesToWrite - 1)); - - // read entries - Enumeration ls = lh.readEntries(0, numEntriesToWrite - 1); - - if (LOG.isDebugEnabled()) { - LOG.debug("*** SYNC READ COMPLETE ***"); - } - - // at this point, Enumeration ls is filled with the returned - // values - int i = 0; - while (ls.hasMoreElements()) { - byte[] origEntryBytes = entries.get(i++); - byte[] retrEntryBytes = ls.nextElement().getEntry(); - - if (LOG.isDebugEnabled()) { - LOG.debug("Original byte entry size: " + origEntryBytes.length); - LOG.debug("Saved byte entry size: " + retrEntryBytes.length); - } - - String origEntry = new String(origEntryBytes, charset); - String retrEntry = new String(retrEntryBytes, charset); - - if (LOG.isDebugEnabled()) { - LOG.debug("Original entry: " + origEntry); - LOG.debug("Retrieved entry: " + retrEntry); - } - - assertTrue("Checking entry " + i + " for equality", origEntry.equals(retrEntry)); - } - assertTrue("Checking number of read entries", i == numEntriesToWrite); - - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - - } - - @Test - public void testReadWriteSyncSingleClient() throws IOException { - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries.add(entry.array()); - lh.addEntry(entry.array()); - } - lh.close(); - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + lh.getLastAddConfirmed()); - } - assertTrue("Verifying number of entries written", lh.getLastAddConfirmed() == (numEntriesToWrite - 1)); - - Enumeration ls = lh.readEntries(0, numEntriesToWrite - 1); - int i = 0; - while (ls.hasMoreElements()) { - ByteBuffer origbb = ByteBuffer.wrap(entries.get(i++)); - Integer origEntry = origbb.getInt(); - ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry()); - Integer retrEntry = result.getInt(); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - LOG.debug("Original entry: " + origEntry); - LOG.debug("Retrieved entry: " + retrEntry); - } - assertTrue("Checking entry " + i + " for equality", origEntry.equals(retrEntry)); - } - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testReadWriteZero() throws IOException { - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - final CountDownLatch completeLatch = new CountDownLatch(numEntriesToWrite); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - - for (int i = 0; i < numEntriesToWrite; i++) { - lh.asyncAddEntry(new byte[0], new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - completeLatch.countDown(); - } - }, null); - } - completeLatch.await(); - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - - /* - * Write a non-zero entry - */ - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - entries.add(entry.array()); - lh.addEntry(entry.array()); - - lh.close(); - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + lh.getLastAddConfirmed()); - } - assertTrue("Verifying number of entries written", lh.getLastAddConfirmed() == numEntriesToWrite); - - Enumeration ls = lh.readEntries(0, numEntriesToWrite - 1); - int i = 0; - while (ls.hasMoreElements()) { - ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry()); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - } - - assertTrue("Checking if entry " + i + " has zero bytes", result.capacity() == 0); - } - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testMultiLedger() throws IOException { - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - lh2 = bkc.createLedger(digestType, ledgerPassword); - - long ledgerId = lh.getId(); - long ledgerId2 = lh2.getId(); - - final CountDownLatch completeLatch = new CountDownLatch(numEntriesToWrite * 2); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - - // bkc.initMessageDigest("SHA1"); - LOG.info("Ledger ID 1: " + lh.getId() + ", Ledger ID 2: " + lh2.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - lh.asyncAddEntry(new byte[0], new AddCallback() { - public void addComplete(int rc2, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rc2); - completeLatch.countDown(); - } - }, null); - lh2.asyncAddEntry(new byte[0], new AddCallback() { - public void addComplete(int rc2, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rc2); - completeLatch.countDown(); - } - }, null); - } - completeLatch.await(); - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - - lh.close(); - lh2.close(); - - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - lh2 = bkc.openLedger(ledgerId2, digestType, ledgerPassword); - - if (LOG.isDebugEnabled()) { - LOG.debug("Number of entries written: " + lh.getLastAddConfirmed() + ", " + lh2.getLastAddConfirmed()); - } - assertTrue("Verifying number of entries written lh (" + lh.getLastAddConfirmed() + ")", lh - .getLastAddConfirmed() == (numEntriesToWrite - 1)); - assertTrue("Verifying number of entries written lh2 (" + lh2.getLastAddConfirmed() + ")", lh2 - .getLastAddConfirmed() == (numEntriesToWrite - 1)); - - Enumeration ls = lh.readEntries(0, numEntriesToWrite - 1); - int i = 0; - while (ls.hasMoreElements()) { - ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry()); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - } - - assertTrue("Checking if entry " + i + " has zero bytes", result.capacity() == 0); - } - lh.close(); - ls = lh2.readEntries(0, numEntriesToWrite - 1); - i = 0; - while (ls.hasMoreElements()) { - ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry()); - if (LOG.isDebugEnabled()) { - LOG.debug("Length of result: " + result.capacity()); - } - - assertTrue("Checking if entry " + i + " has zero bytes", result.capacity() == 0); - } - lh2.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testReadWriteAsyncLength() throws IOException { - SyncObj sync = new SyncObj(); - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - for (int i = 0; i < numEntriesToWrite; i++) { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.asyncAddEntry(entry.array(), this, sync); - } - - // wait for all entries to be acknowledged - synchronized (sync) { - while (sync.counter < numEntriesToWrite) { - if (LOG.isDebugEnabled()) { - LOG.debug("Entries counter = " + sync.counter); - } - sync.wait(); - } - assertEquals("Error adding", BKException.Code.OK, sync.getReturnCode()); - } - long length = numEntriesToWrite * 4; - assertTrue("Ledger length before closing: " + lh.getLength(), lh.getLength() == length); - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - - // *** WRITING PART COMPLETE // READ PART BEGINS *** - - // open ledger - lh = bkc.openLedger(ledgerId, digestType, ledgerPassword); - assertTrue("Ledger length after opening: " + lh.getLength(), lh.getLength() == length); - - - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - private long writeNEntriesLastWriteSync(LedgerHandle lh, int numToWrite) throws Exception { - final CountDownLatch completeLatch = new CountDownLatch(numToWrite - 1); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - - ByteBuffer entry = ByteBuffer.allocate(4); - for (int i = 0; i < numToWrite - 1; i++) { - entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.asyncAddEntry(entry.array(), new AddCallback() { - public void addComplete(int rccb, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rccb); - completeLatch.countDown(); - } - }, null); - } - completeLatch.await(); - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - - entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.addEntry(entry.array()); - return lh.getLastAddConfirmed(); - } - - @Test - public void testReadFromOpenLedger() throws Exception { - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - - long lac = writeNEntriesLastWriteSync(lh, numEntriesToWrite); - - LedgerHandle lhOpen = bkc.openLedgerNoRecovery(ledgerId, digestType, ledgerPassword); - // no recovery opened ledger 's last confirmed entry id is less than written - // and it just can read until (i-1) - long toRead = lac - 1; - - Enumeration readEntry = lhOpen.readEntries(toRead, toRead); - assertTrue("Enumeration of ledger entries has no element", readEntry.hasMoreElements()); - LedgerEntry e = readEntry.nextElement(); - assertEquals(toRead, e.getEntryId()); - assertArrayEquals(entries.get((int) toRead), e.getEntry()); - // should not written to a read only ledger - try { - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - lhOpen.addEntry(entry.array()); - fail("Should have thrown an exception here"); - } catch (BKException.BKIllegalOpException bkioe) { - // this is the correct response - } catch (Exception ex) { - LOG.error("Unexpected exception", ex); - fail("Unexpected exception"); - } - // close read only ledger should not change metadata - lhOpen.close(); - - lac = writeNEntriesLastWriteSync(lh, numEntriesToWrite); - - assertEquals("Last confirmed add: ", lac, (numEntriesToWrite * 2) - 1); - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - /* - * Asynchronous call to read last confirmed entry - */ - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - - writeNEntriesLastWriteSync(lh, numEntriesToWrite); - - SyncObj sync = new SyncObj(); - lh.asyncReadLastConfirmed(this, sync); - - // Wait for for last confirmed - synchronized (sync) { - while (sync.lastConfirmed == -1) { - if (LOG.isDebugEnabled()) { - LOG.debug("Counter = " + sync.lastConfirmed); - } - sync.wait(); - } - assertEquals("Error reading", BKException.Code.OK, sync.getReturnCode()); - } - - assertEquals("Last confirmed add", sync.lastConfirmed, (numEntriesToWrite - 2)); - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testReadFromOpenLedgerOpenOnce() throws Exception { - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - LedgerHandle lhOpen = bkc.openLedgerNoRecovery(ledgerId, digestType, ledgerPassword); - writeNEntriesLastWriteSync(lh, numEntriesToWrite / 2); - - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - // no recovery opened ledger 's last confirmed entry id is - // less than written - // and it just can read until (i-1) - int toRead = numEntriesToWrite / 2 - 2; - - long readLastConfirmed = lhOpen.readLastConfirmed(); - assertTrue(readLastConfirmed != 0); - Enumeration readEntry = lhOpen.readEntries(toRead, toRead); - assertTrue("Enumeration of ledger entries has no element", readEntry.hasMoreElements()); - LedgerEntry e = readEntry.nextElement(); - assertEquals(toRead, e.getEntryId()); - assertArrayEquals(entries.get(toRead), e.getEntry()); - // should not written to a read only ledger - try { - lhOpen.addEntry(entry.array()); - fail("Should have thrown an exception here"); - } catch (BKException.BKIllegalOpException bkioe) { - // this is the correct response - } catch (Exception ex) { - LOG.error("Unexpected exception", ex); - fail("Unexpected exception"); - } - writeNEntriesLastWriteSync(lh, numEntriesToWrite / 2); - - long last = lh.readLastConfirmed(); - assertTrue("Last confirmed add: " + last, last == (numEntriesToWrite - 2)); - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - // close read only ledger should not change metadata - lhOpen.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testReadFromOpenLedgerZeroAndOne() throws Exception { - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - LedgerHandle lhOpen = bkc.openLedgerNoRecovery(ledgerId, digestType, ledgerPassword); - - /* - * We haven't written anything, so it should be empty. - */ - if (LOG.isDebugEnabled()) { - LOG.debug("Checking that it is empty"); - } - long readLastConfirmed = lhOpen.readLastConfirmed(); - assertTrue("Last confirmed has the wrong value", - readLastConfirmed == LedgerHandle.INVALID_ENTRY_ID); - - /* - * Writing one entry. - */ - if (LOG.isDebugEnabled()) { - LOG.debug("Going to write one entry"); - } - ByteBuffer entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.addEntry(entry.array()); - - /* - * The hint should still indicate that there is no confirmed - * add. - */ - if (LOG.isDebugEnabled()) { - LOG.debug("Checking that it is still empty even after writing one entry"); - } - readLastConfirmed = lhOpen.readLastConfirmed(); - assertTrue(readLastConfirmed == LedgerHandle.INVALID_ENTRY_ID); - - /* - * Adding one more, and this time we should expect to - * see one entry. - */ - entry = ByteBuffer.allocate(4); - entry.putInt(rng.nextInt(maxInt)); - entry.position(0); - - entries.add(entry.array()); - entriesSize.add(entry.array().length); - lh.addEntry(entry.array()); - - LOG.info("Checking that it has an entry"); - readLastConfirmed = lhOpen.readLastConfirmed(); - assertTrue(readLastConfirmed == 0L); - - // close ledger - lh.close(); - // close read only ledger should not change metadata - lhOpen.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testWriteUsingReadOnlyHandle() throws Exception { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - - long lac = writeNEntriesLastWriteSync(lh, numEntriesToWrite); - LedgerHandle lhOpen = bkc.openLedgerNoRecovery(ledgerId, digestType, ledgerPassword); - - // addEntry on ReadOnlyHandle should fail - CountDownLatch latch = new CountDownLatch(1); - final int[] rcArray = { 0 }; - lhOpen.asyncAddEntry("".getBytes(), new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - rcArray[0] = rc; - latch.countDown(); - } - }, latch); - latch.await(); - if (rcArray[0] != BKException.Code.IllegalOpException) { - Assert.fail("Test1 - asyncAddOperation is supposed to be failed, but it got following rc - " - + KeeperException.Code.get(rcArray[0])); - } - - // addEntry on ReadOnlyHandle should fail - latch = new CountDownLatch(1); - rcArray[0] = 0; - lhOpen.asyncAddEntry("".getBytes(), 0, 0, new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - rcArray[0] = rc; - latch.countDown(); - } - }, latch); - latch.await(); - if (rcArray[0] != BKException.Code.IllegalOpException) { - Assert.fail( - "Test2 - asyncAddOperation is supposed to fail with IllegalOpException, but it got following rc - " - + KeeperException.Code.get(rcArray[0])); - } - - // close readonlyhandle - latch = new CountDownLatch(1); - rcArray[0] = 0; - lhOpen.asyncClose(new CloseCallback() { - @Override - public void closeComplete(int rc, LedgerHandle lh, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - rcArray[0] = rc; - latch.countDown(); - } - }, latch); - latch.await(); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test3 - asyncClose failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - - // close of readonlyhandle should not affect the writehandle - writeNEntriesLastWriteSync(lh, 5); - lh.close(); - } - - @Test - public void testLedgerHandle() throws Exception { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - - long lac = writeNEntriesLastWriteSync(lh, 5); - - // doing addEntry with entryid using regular Ledgerhandle should fail - CountDownLatch latch = new CountDownLatch(1); - final int[] rcArray = { 0 }; - lh.asyncAddEntry(lac + 1, "".getBytes(), new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - rcArray[0] = rc; - latch.countDown(); - } - }, latch); - latch.await(); - if (rcArray[0] != BKException.Code.IllegalOpException) { - Assert.fail( - "Test1 - addEntry with EntryID is expected to fail with IllegalOpException, " - + "but it got following rc - " + KeeperException.Code.get(rcArray[0])); - } - - // doing addEntry with entryid using regular Ledgerhandle should fail - latch = new CountDownLatch(1); - rcArray[0] = 0; - lh.asyncAddEntry(lac + 1, "".getBytes(), 0, 0, new AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - rcArray[0] = rc; - latch.countDown(); - } - }, latch); - latch.await(); - if (rcArray[0] != BKException.Code.IllegalOpException) { - Assert.fail( - "Test2 - addEntry with EntryID is expected to fail with IllegalOpException," - + "but it got following rc - " + KeeperException.Code.get(rcArray[0])); - } - - // doing addEntry with entryid using regular Ledgerhandle should fail - try { - lh.addEntry(lac + 1, "".getBytes()); - Assert.fail("Test3 - addEntry with EntryID is expected to fail"); - } catch (BKIllegalOpException E) { - } - - // doing addEntry with entryid using regular Ledgerhandle should fail - try { - lh.addEntry(lac + 1, "".getBytes(), 0, 0); - Assert.fail("Test4 - addEntry with EntryID is expected to fail"); - } catch (BKIllegalOpException E) { - } - - lh.close(); - } - - @Test - public void testLastConfirmedAdd() throws Exception { - try { - // Create a ledger - lh = bkc.createLedger(digestType, ledgerPassword); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - - writeNEntriesLastWriteSync(lh, numEntriesToWrite); - long last = lh.readLastConfirmed(); - assertTrue("Last confirmed add: " + last, last == (numEntriesToWrite - 2)); - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - /* - * Asynchronous call to read last confirmed entry - */ - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - writeNEntriesLastWriteSync(lh, numEntriesToWrite); - - SyncObj sync = new SyncObj(); - lh.asyncReadLastConfirmed(this, sync); - - // Wait for for last confirmed - synchronized (sync) { - while (sync.lastConfirmed == LedgerHandle.INVALID_ENTRY_ID) { - if (LOG.isDebugEnabled()) { - LOG.debug("Counter = " + sync.lastConfirmed); - } - sync.wait(); - } - assertEquals("Error reading", BKException.Code.OK, sync.getReturnCode()); - } - - assertTrue("Last confirmed add: " + sync.lastConfirmed, sync.lastConfirmed == (numEntriesToWrite - 2)); - - if (LOG.isDebugEnabled()) { - LOG.debug("*** WRITE COMPLETE ***"); - } - // close ledger - lh.close(); - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void testReadLastConfirmed() throws Exception { - // Create a ledger and add entries - lh = bkc.createLedger(digestType, ledgerPassword); - // bkc.initMessageDigest("SHA1"); - ledgerId = lh.getId(); - LOG.info("Ledger ID: " + lh.getId()); - long previousLAC = writeNEntriesLastWriteSync(lh, 5); - - // add more entries after opening ReadonlyLedgerHandle - LedgerHandle lhOpen = bkc.openLedgerNoRecovery(ledgerId, digestType, ledgerPassword); - long currentLAC = writeNEntriesLastWriteSync(lh, 5); - - // get LAC instance variable of ReadHandle and verify if it is equal to (previousLAC - 1) - long readLAC = lhOpen.getLastAddConfirmed(); - Assert.assertEquals("Test1 - For ReadHandle LAC", (previousLAC - 1), readLAC); - - // close the write LedgerHandle and sleep for 500 msec to make sure all close watchers are called - lh.close(); - Thread.sleep(500); - - // now call asyncReadLastConfirmed and verify if it is equal to currentLAC - CountDownLatch latch = new CountDownLatch(1); - final int[] rcArray = { 0 }; - final long[] lastConfirmedArray = { 0 }; - lhOpen.asyncReadLastConfirmed(new ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - rcArray[0] = rc; - lastConfirmedArray[0] = lastConfirmed; - latch.countDown(); - } - }, latch); - latch.await(); - Assert.assertEquals("Test3 - asyncReadLastConfirmed response", KeeperException.Code.OK.intValue(), rcArray[0]); - Assert.assertEquals("Test3 - ReadLAC", currentLAC, lastConfirmedArray[0]); - - // similarly try calling asyncTryReadLastConfirmed and verify if it is equal to currentLAC - latch = new CountDownLatch(1); - rcArray[0] = 0; - lastConfirmedArray[0] = 0; - lhOpen.asyncTryReadLastConfirmed(new ReadLastConfirmedCallback() { - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - CountDownLatch latch = (CountDownLatch) ctx; - rcArray[0] = rc; - lastConfirmedArray[0] = lastConfirmed; - latch.countDown(); - } - }, latch); - latch.await(); - Assert.assertEquals("Test4 - asyncTryReadLastConfirmed response", KeeperException.Code.OK.intValue(), - rcArray[0]); - Assert.assertEquals("Test4 - ReadLAC", currentLAC, lastConfirmedArray[0]); - - // similarly try calling tryReadLastConfirmed and verify if it is equal to currentLAC - long tryReadLAC = lhOpen.tryReadLastConfirmed(); - Assert.assertEquals("Test5 - ReadLAC", currentLAC, tryReadLAC); - } - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - SyncObj sync = (SyncObj) ctx; - sync.setReturnCode(rc); - synchronized (sync) { - sync.counter++; - sync.notify(); - } - } - - @Override - public void readComplete(int rc, LedgerHandle lh, Enumeration seq, Object ctx) { - SyncObj sync = (SyncObj) ctx; - sync.setLedgerEntries(seq); - sync.setReturnCode(rc); - synchronized (sync) { - sync.value = true; - sync.notify(); - } - } - - @Override - public void readLastConfirmedComplete(int rc, long lastConfirmed, Object ctx) { - SyncObj sync = (SyncObj) ctx; - sync.setReturnCode(rc); - synchronized (sync) { - sync.lastConfirmed = lastConfirmed; - sync.notify(); - } - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - rng = new Random(System.currentTimeMillis()); // Initialize the Random - // Number Generator - entries = new ArrayList(); // initialize the entries list - entriesSize = new ArrayList(); - } - - /* Clean up a directory recursively */ - protected boolean cleanUpDir(File dir) { - if (dir.isDirectory()) { - LOG.info("Cleaning up " + dir.getName()); - String[] children = dir.list(); - for (String string : children) { - boolean success = cleanUpDir(new File(dir, string)); - if (!success) { - return false; - } - } - } - // The directory is now empty so delete it - return dir.delete(); - } - - /** - * Used for testing purposes, void. - */ - class EmptyWatcher implements Watcher { - @Override - public void process(WatchedEvent event) { - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieZKExpireTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieZKExpireTest.java deleted file mode 100644 index 808b7e8f900..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieZKExpireTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.UnpooledByteBufAllocator; -import java.io.File; -import java.util.HashSet; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.MockUncleanShutdownDetection; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.PortManager; -import org.junit.Test; - -/** - * Test bookie expiration. - */ -@Slf4j -public class BookieZKExpireTest extends BookKeeperClusterTestCase { - - public BookieZKExpireTest() { - super(0); - } - - /* - Should recover from request timeout. - */ - @Test - @SuppressWarnings("deprecation") - public void testBookieServerZKRequestTimeoutBehaviour() throws Exception { - // 6000 is minimum due to default tick time - System.setProperty("zookeeper.request.timeout", "6000"); - baseConf.setZkTimeout(24000); - baseClientConf.setZkTimeout(24000); - BookieServer server = null; - try { - File f = tmpDirs.createNew("bookieserver", "test"); - - HashSet threadset = new HashSet(); - int threadCount = Thread.activeCount(); - Thread[] threads = new Thread[threadCount * 2]; - threadCount = Thread.enumerate(threads); - for (int i = 0; i < threadCount; i++) { - if (threads[i].getName().indexOf("SendThread") != -1) { - threadset.add(threads[i]); - } - } - - ServerConfiguration conf = newServerConfiguration(PortManager.nextFreePort(), f, new File[] { f }); - server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - - int secondsToWait = 5; - while (!server.isRunning()) { - Thread.sleep(1000); - if (secondsToWait-- <= 0) { - fail("Bookie never started"); - } - } - Thread sendthread = null; - threadCount = Thread.activeCount(); - threads = new Thread[threadCount * 2]; - threadCount = Thread.enumerate(threads); - for (int i = 0; i < threadCount; i++) { - if (threads[i].getName().indexOf("SendThread") != -1 - && !threadset.contains(threads[i])) { - sendthread = threads[i]; - break; - } - } - assertNotNull("Send thread not found", sendthread); - - log.info("Suspending threads"); - sendthread.suspend(); - Thread.sleep(12000); - log.info("Resuming threads"); - sendthread.resume(); - - // allow watcher thread to run - Thread.sleep(3000); - assertTrue("Bookie should not shutdown on zk timeout", server.isBookieRunning()); - assertTrue("Bookie Server should not shutdown on zk timeout", server.isRunning()); - } finally { - System.clearProperty("zookeeper.request.timeout"); - server.shutdown(); - } - } - - /* - Bookie cannot recover from ZK Client's SessionExpired error. - In this case the ZK client must be recreated, reconnect does not work. - Attempt to reconnect by BookieStateManager's RegistrationManager listener - will fail (even if retry it many times). - */ - @FlakyTest(value = "https://github.com/apache/bookkeeper/issues/4142") - @SuppressWarnings("deprecation") - public void testBookieServerZKSessionExpireBehaviour() throws Exception { - // 6000 is minimum due to default tick time - System.setProperty("zookeeper.request.timeout", "0"); - baseConf.setZkTimeout(6000); - baseClientConf.setZkTimeout(6000); - BookieServer server = null; - try { - File f = tmpDirs.createNew("bookieserver", "test"); - - HashSet threadset = new HashSet(); - int threadCount = Thread.activeCount(); - Thread[] threads = new Thread[threadCount * 2]; - threadCount = Thread.enumerate(threads); - for (int i = 0; i < threadCount; i++) { - if (threads[i].getName().indexOf("SendThread") != -1) { - threadset.add(threads[i]); - } - } - - ServerConfiguration conf = newServerConfiguration(PortManager.nextFreePort(), f, new File[] { f }); - server = new BookieServer( - conf, new TestBookieImpl(conf), - NullStatsLogger.INSTANCE, UnpooledByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - - int secondsToWait = 5; - while (!server.isRunning()) { - Thread.sleep(1000); - if (secondsToWait-- <= 0) { - fail("Bookie never started"); - } - } - Thread sendthread = null; - threadCount = Thread.activeCount(); - threads = new Thread[threadCount * 2]; - threadCount = Thread.enumerate(threads); - for (int i = 0; i < threadCount; i++) { - if (threads[i].getName().indexOf("SendThread") != -1 - && !threadset.contains(threads[i])) { - sendthread = threads[i]; - break; - } - } - assertNotNull("Send thread not found", sendthread); - - log.info("Suspending threads"); - sendthread.suspend(); - Thread.sleep(2L * conf.getZkTimeout()); - log.info("Resuming threads"); - sendthread.resume(); - - // allow watcher thread to run - Thread.sleep(3000); - assertFalse("Bookie should shutdown on losing zk session", server.isBookieRunning()); - assertFalse("Bookie Server should shutdown on losing zk session", server.isRunning()); - } finally { - System.clearProperty("zookeeper.request.timeout"); - server.shutdown(); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/CloseTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/CloseTest.java deleted file mode 100644 index d3c88480207..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/CloseTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.junit.Test; - -/** - * This unit test tests closing ledgers sequentially. It creates 4 ledgers, then - * write 1000 entries to each ledger and close it. - * - */ -public class CloseTest extends BookKeeperClusterTestCase { - - private final DigestType digestType; - - public CloseTest() { - super(3); - this.digestType = DigestType.CRC32; - } - - @Test - public void testClose() throws Exception { - - /* - * Create 4 ledgers. - */ - int numLedgers = 4; - int numMsgs = 100; - - LedgerHandle[] lh = new LedgerHandle[numLedgers]; - for (int i = 0; i < numLedgers; i++) { - lh[i] = bkc.createLedger(digestType, "".getBytes()); - } - - String tmp = "BookKeeper is cool!"; - - /* - * Write 1000 entries to lh1. - */ - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lh[j].addEntry(tmp.getBytes()); - } - } - - for (int i = 0; i < numLedgers; i++) { - - lh[i].close(); - } - } - - @Test - public void testCloseByOthers() throws Exception { - - int numLedgers = 1; - int numMsgs = 10; - - LedgerHandle lh = bkc.createLedger(digestType, "".getBytes()); - - String tmp = "BookKeeper is cool!"; - - /* - * Write 10 entries to lh. - */ - for (int i = 0; i < numMsgs; i++) { - lh.addEntry(tmp.getBytes()); - } - - // other one close the entries - LedgerHandle lh2 = bkc.openLedger(lh.getId(), digestType, "".getBytes()); - - // so the ledger would be closed, the metadata is changed - // the original ledger handle should be able to close it successfully - lh2.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConcurrentLedgerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConcurrentLedgerTest.java deleted file mode 100644 index 11b7fe80d04..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConcurrentLedgerTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Semaphore; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests writing to concurrent ledgers. - */ -public class ConcurrentLedgerTest { - private static final Logger LOG = LoggerFactory.getLogger(ConcurrentLedgerTest.class); - - Bookie bookie; - File txnDir, ledgerDir; - int recvTimeout = 10000; - Semaphore throttle; - ServerConfiguration conf = TestBKConfiguration.newServerConfiguration(); - final List tempDirs = new ArrayList(); - - private File createTempDir(String prefix, String suffix, File parent) throws IOException { - File dir = File.createTempFile(prefix, suffix, parent); - dir.delete(); - tempDirs.add(dir); - return dir; - } - - @Before - public void setUp() throws Exception { - String txnDirName = System.getProperty("txnDir"); - if (txnDirName != null) { - txnDir = new File(txnDirName); - } - String ledgerDirName = System.getProperty("ledgerDir"); - if (ledgerDirName != null) { - ledgerDir = new File(ledgerDirName); - } - File tmpFile = createTempDir("book", ".txn", txnDir); - txnDir = new File(tmpFile.getParent(), tmpFile.getName() + ".dir"); - txnDir.mkdirs(); - tmpFile = createTempDir("book", ".ledger", ledgerDir); - ledgerDir = new File(tmpFile.getParent(), tmpFile.getName() + ".dir"); - ledgerDir.mkdirs(); - - conf.setBookiePort(5000); - conf.setMetadataServiceUri(null); - conf.setJournalDirName(txnDir.getPath()); - conf.setLedgerDirNames(new String[] { ledgerDir.getPath() }); - bookie = new TestBookieImpl(conf); - bookie.start(); - } - - static void recursiveDelete(File f) { - if (f.isFile()) { - f.delete(); - } else { - for (File i: f.listFiles()) { - recursiveDelete(i); - } - f.delete(); - } - } - - @After - public void tearDown() { - bookie.shutdown(); - recursiveDelete(txnDir); - recursiveDelete(ledgerDir); - } - - byte[] zeros = new byte[16]; - - int iterations = 51; - { - String iterationsString = System.getProperty("iterations"); - if (iterationsString != null) { - iterations = Integer.parseInt(iterationsString); - } - } - int iterationStep = 25; - { - String iterationsString = System.getProperty("iterationStep"); - if (iterationsString != null) { - iterationStep = Integer.parseInt(iterationsString); - } - } - @Test - public void testConcurrentWrite() throws IOException, InterruptedException, BookieException { - int size = 1024; - int totalwrites = 128; - if (System.getProperty("totalwrites") != null) { - totalwrites = Integer.parseInt(System.getProperty("totalwrites")); - } - LOG.info("Running up to " + iterations + " iterations"); - LOG.info("Total writes = " + totalwrites); - int ledgers; - for (ledgers = 1; ledgers <= iterations; ledgers += iterationStep) { - long duration = doWrites(ledgers, size, totalwrites); - LOG.info(totalwrites + " on " + ledgers + " took " + duration + " ms"); - } - LOG.info("ledgers " + ledgers); - for (ledgers = 1; ledgers <= iterations; ledgers += iterationStep) { - long duration = doReads(ledgers, size, totalwrites); - LOG.info(ledgers + " read " + duration + " ms"); - } - } - - private long doReads(int ledgers, int size, int totalwrites) - throws IOException, InterruptedException, BookieException { - long start = System.currentTimeMillis(); - for (int i = 1; i <= totalwrites / ledgers; i++) { - for (int j = 1; j <= ledgers; j++) { - ByteBuf entry = bookie.readEntry(j, i); - // skip the ledger id and the entry id - entry.readLong(); - entry.readLong(); - assertEquals(j + "@" + i, j + 2, entry.readLong()); - assertEquals(j + "@" + i, i + 3, entry.readLong()); - } - } - long finish = System.currentTimeMillis(); - return finish - start; - } - private long doWrites(int ledgers, int size, int totalwrites) - throws IOException, InterruptedException, BookieException { - throttle = new Semaphore(10000); - WriteCallback cb = new WriteCallback() { - @Override - public void writeComplete(int rc, long ledgerId, long entryId, - BookieId addr, Object ctx) { - AtomicInteger counter = (AtomicInteger) ctx; - counter.getAndIncrement(); - throttle.release(); - } - }; - AtomicInteger counter = new AtomicInteger(); - long start = System.currentTimeMillis(); - for (int i = 1; i <= totalwrites / ledgers; i++) { - for (int j = 1; j <= ledgers; j++) { - ByteBuffer bytes = ByteBuffer.allocate(size); - bytes.putLong(j); - bytes.putLong(i); - bytes.putLong(j + 2); - bytes.putLong(i + 3); - bytes.put(("This is ledger " + j + " entry " + i).getBytes()); - bytes.position(0); - bytes.limit(bytes.capacity()); - throttle.acquire(); - bookie.addEntry(Unpooled.wrappedBuffer(bytes), false, cb, counter, zeros); - } - } - long finish = System.currentTimeMillis(); - return finish - start; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConditionalSetTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConditionalSetTest.java deleted file mode 100644 index db8dcd9223c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConditionalSetTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import java.io.IOException; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.zookeeper.KeeperException; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests conditional set of the ledger metadata znode. - */ -public class ConditionalSetTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(ConditionalSetTest.class); - - byte[] entry; - private final DigestType digestType; - BookKeeper bkcReader; - - public ConditionalSetTest() { - super(3); - this.digestType = DigestType.CRC32; - } - - @Override - @Before - public void setUp() throws IOException, Exception { - super.setUp(); - entry = new byte[10]; // initialize the entries list - this.bkcReader = new BookKeeperTestClient(baseClientConf); - } - - /** - * Opens a ledger before the ledger writer, which triggers ledger recovery. - * When the ledger writer tries to close the ledger, the close operation - * should fail. - * - * - * @throws IOException - * @throws InterruptedException - * @throws BKException - * @throws KeeperException - */ - - @Test - public void testConditionalSet() throws IOException, InterruptedException, - BKException, KeeperException { - LedgerHandle lhWrite = bkc.createLedger(digestType, new byte[] { 'a', - 'b' }); - long ledgerId = lhWrite.getId(); - if (LOG.isDebugEnabled()) { - LOG.debug("Ledger ID: {}", ledgerId); - } - for (int i = 0; i < 10; i++) { - if (LOG.isDebugEnabled()) { - LOG.debug("Adding entry: " + i); - } - lhWrite.addEntry(entry); - } - - /* - * Open a ledger for reading, which triggers recovery, since the ledger - * is still open. - */ - if (LOG.isDebugEnabled()) { - LOG.debug("Instantiating new bookkeeper client."); - } - LedgerHandle lhRead = bkcReader.openLedger(lhWrite.getId(), digestType, - new byte[] { 'a', 'b' }); - if (LOG.isDebugEnabled()) { - LOG.debug("Opened the ledger already"); - } - - /* - * Writer tries to close the ledger, and it should succeed as recovery closed - * the ledger already, but with the correct LAC and length - */ - lhWrite.close(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConfigurationTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConfigurationTest.java deleted file mode 100644 index 5eb3c82c098..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConfigurationTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertEquals; - -import org.apache.bookkeeper.conf.AbstractConfiguration; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.junit.Test; - -/** - * Test the configuration class. - */ -public class ConfigurationTest { - - static { - // this property is read when AbstractConfiguration class is loaded. - // this test will work as expected only using a new JVM (or classloader) for the test - System.setProperty(AbstractConfiguration.READ_SYSTEM_PROPERTIES_PROPERTY, "true"); - } - - @Test - public void testConfigurationOverwrite() { - System.clearProperty("metadataServiceUri"); - - ServerConfiguration conf = new ServerConfiguration(); - assertEquals(null, conf.getMetadataServiceUriUnchecked()); - - // override setting from property - System.setProperty("metadataServiceUri", "zk://server:2181/ledgers"); - // it affects previous created configurations, if the setting is not overwrite - assertEquals("zk://server:2181/ledgers", conf.getMetadataServiceUriUnchecked()); - - ServerConfiguration conf2 = new ServerConfiguration(); - assertEquals("zk://server:2181/ledgers", conf2.getMetadataServiceUriUnchecked()); - - System.clearProperty("metadataServiceUri"); - - // load other configuration - ServerConfiguration newConf = new ServerConfiguration(); - assertEquals(null, newConf.getMetadataServiceUriUnchecked()); - newConf.setMetadataServiceUri("zk://newserver:2181/ledgers"); - assertEquals("zk://newserver:2181/ledgers", newConf.getMetadataServiceUriUnchecked()); - conf2.loadConf(newConf); - assertEquals("zk://newserver:2181/ledgers", conf2.getMetadataServiceUriUnchecked()); - } - - @Test - public void testGetZkServers() { - System.setProperty("metadataServiceUri", "zk://server1:port1;server2:port2/ledgers"); - ServerConfiguration conf = new ServerConfiguration(); - ClientConfiguration clientConf = new ClientConfiguration(); - assertEquals("zookeeper connect string doesn't match in server configuration", - "zk://server1:port1;server2:port2/ledgers", conf.getMetadataServiceUriUnchecked()); - assertEquals("zookeeper connect string doesn't match in client configuration", - "zk://server1:port1;server2:port2/ledgers", clientConf.getMetadataServiceUriUnchecked()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ForceReadOnlyBookieTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ForceReadOnlyBookieTest.java deleted file mode 100644 index b00fc19a854..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ForceReadOnlyBookieTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.util.Enumeration; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test to verify force start readonly bookie. - */ -public class ForceReadOnlyBookieTest extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(ForceReadOnlyBookieTest.class); - public ForceReadOnlyBookieTest() { - super(2); - baseConf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - baseConf.setEntryLogFilePreAllocationEnabled(false); - } - - /** - * Check force start readonly bookie. - */ - @Test - public void testBookieForceStartAsReadOnly() throws Exception { - // create ledger, add entries - LedgerHandle ledger = bkc.createLedger(2, 2, DigestType.MAC, - "".getBytes()); - for (int i = 0; i < 10; i++) { - ledger.addEntry("data".getBytes()); - } - ledger.close(); - LOG.info("successed prepare"); - - // start bookie 1 as readonly - confByIndex(1).setReadOnlyModeEnabled(true); - confByIndex(1).setForceReadOnlyBookie(true); - restartBookies(); - Bookie bookie = serverByIndex(1).getBookie(); - - assertTrue("Bookie should be running and in readonly mode", - bookie.isRunning() && bookie.isReadOnly()); - LOG.info("successed force start ReadOnlyBookie"); - - // Check new bookie with readonly mode enabled. - File[] ledgerDirs = confByIndex(1).getLedgerDirs(); - assertEquals("Only one ledger dir should be present", 1, ledgerDirs.length); - - // kill the writable bookie - killBookie(0); - // read entry from read only bookie - Enumeration readEntries = ledger.readEntries(0, 9); - while (readEntries.hasMoreElements()) { - LedgerEntry entry = readEntries.nextElement(); - assertEquals("Entry should contain correct data", "data", - new String(entry.getEntry())); - } - LOG.info("successed read entry from ReadOnlyBookie"); - - // test will not transfer to Writable mode. - LedgerDirsManager ledgerDirsManager = ((BookieImpl) bookie).getLedgerDirsManager(); - ledgerDirsManager.addToWritableDirs(new File(ledgerDirs[0], "current"), true); - assertTrue("Bookie should be running and in readonly mode", - bookie.isRunning() && bookie.isReadOnly()); - LOG.info("successed: bookie still readonly"); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerCreateDeleteTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerCreateDeleteTest.java deleted file mode 100644 index da342c863df..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerCreateDeleteTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.apache.bookkeeper.test; - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.junit.Before; -import org.junit.Test; - -/** - * Test Create/Delete ledgers. - */ -public class LedgerCreateDeleteTest extends BookKeeperClusterTestCase { - - public LedgerCreateDeleteTest() { - super(1); - } - - @Override - @Before - public void setUp() throws Exception { - baseConf.setOpenFileLimit(1); - super.setUp(); - } - - @Test - public void testCreateDeleteLedgers() throws Exception { - int numLedgers = 3; - ArrayList ledgers = new ArrayList(); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(1, 1, DigestType.CRC32, "bk is cool".getBytes()); - for (int j = 0; j < 5; j++) { - lh.addEntry("just test".getBytes()); - } - ledgers.add(lh.getId()); - lh.close(); - } - for (long ledgerId : ledgers) { - bkc.deleteLedger(ledgerId); - } - ledgers.clear(); - Thread.sleep(baseConf.getGcWaitTime() * 2); - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(1, 1, DigestType.CRC32, "bk is cool".getBytes()); - for (int j = 0; j < 5; j++) { - lh.addEntry("just test".getBytes()); - } - ledgers.add(lh.getId()); - lh.close(); - } - } - - @Test - public void testCreateLedgerWithBKNotEnoughBookiesException() throws Exception { - try { - bkc.createLedger(2, 2, DigestType.CRC32, "bk is cool".getBytes()); - fail("Should be able to throw BKNotEnoughBookiesException"); - } catch (BKException.BKNotEnoughBookiesException bkn) { - // expected - } - } - - @Test - public void testCreateLedgerWithZKException() throws Exception { - stopZKCluster(); - try { - bkc.createLedger(1, 1, DigestType.CRC32, "bk is cool".getBytes()); - fail("Should be able to throw ZKException"); - } catch (BKException.ZKException zke) { - // expected - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerDeleteTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerDeleteTest.java deleted file mode 100644 index a638fa73830..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerDeleteTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertFalse; - -import java.io.File; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.util.TestUtils; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class tests the ledger delete functionality both from the BookKeeper - * client and the server side. - */ -public class LedgerDeleteTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(LedgerDeleteTest.class); - DigestType digestType; - - public LedgerDeleteTest() { - this("org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory"); - } - - LedgerDeleteTest(String ledgerManagerFactory) { - super(1); - LOG.info("Running test case using ledger manager : " + ledgerManagerFactory); - this.digestType = DigestType.CRC32; - // set ledger manager name - baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - baseClientConf.setLedgerManagerFactoryClassName(ledgerManagerFactory); - } - - @Before - @Override - public void setUp() throws Exception { - // Set up the configuration properties needed. - baseConf.setEntryLogSizeLimit(2 * 1024 * 1024L); - baseConf.setGcWaitTime(1000); - baseConf.setEntryLogFilePreAllocationEnabled(false); - baseConf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - super.setUp(); - } - - /** - * Common method to create ledgers and write entries to them. - */ - private LedgerHandle[] writeLedgerEntries(int numLedgers, int msgSize, int numMsgs) throws Exception { - // Create the ledgers - LedgerHandle[] lhs = new LedgerHandle[numLedgers]; - for (int i = 0; i < numLedgers; i++) { - lhs[i] = bkc.createLedger(1, 1, digestType, "".getBytes()); - } - - // Create a dummy message string to write as ledger entries - StringBuilder msgSB = new StringBuilder(); - for (int i = 0; i < msgSize; i++) { - msgSB.append("a"); - } - String msg = msgSB.toString(); - final CountDownLatch completeLatch = new CountDownLatch(numMsgs * numLedgers); - final AtomicInteger rc = new AtomicInteger(BKException.Code.OK); - // Write all of the entries for all of the ledgers - for (int i = 0; i < numMsgs; i++) { - for (int j = 0; j < numLedgers; j++) { - lhs[j].asyncAddEntry(msg.getBytes(), new AddCallback() { - public void addComplete(int rc2, LedgerHandle lh, long entryId, Object ctx) { - rc.compareAndSet(BKException.Code.OK, rc2); - completeLatch.countDown(); - } - }, null); - } - } - completeLatch.await(); - if (rc.get() != BKException.Code.OK) { - throw BKException.create(rc.get()); - } - - // Return the ledger handles to the inserted ledgers and entries - return lhs; - } - - /** - * This test writes enough ledger entries to roll over the entry log file. - * It will then delete all of the ledgers from the client and let the - * server's EntryLogger garbage collector thread delete the initial entry - * log file. - * - * @throws Exception - */ - @Test - public void testLedgerDelete() throws Exception { - // Write enough ledger entries so that we roll over the initial entryLog (0.log) - LedgerHandle[] lhs = writeLedgerEntries(3, 1024, 1024); - // restart bookies to force rolling entry log files - restartBookies(); - - List ledgerDirectories = bookieLedgerDirs(); - // Delete all of these ledgers from the BookKeeper client - for (LedgerHandle lh : lhs) { - bkc.deleteLedger(lh.getId()); - } - LOG.info("Finished deleting all ledgers so waiting for the GC thread to clean up the entryLogs"); - Thread.sleep(5000); - - // Verify that the first entry log (0.log) has been deleted from all of the Bookie Servers. - for (File ledgerDirectory : ledgerDirectories) { - assertFalse("Found the entry log file (0.log) that should have been deleted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0)); - } - } - - /** - * This test is similar to testLedgerDelete() except it will stop and - * restart the Bookie Servers after it has written out the ledger entries. - * On restart, there will be existing entry logs and ledger index files for - * the EntryLogger and LedgerCache to read and store into memory. - * - * @throws Exception - */ - @Test - public void testLedgerDeleteWithExistingEntryLogs() throws Exception { - // Write enough ledger entries so that we roll over the initial entryLog (0.log) - LedgerHandle[] lhs = writeLedgerEntries(3, 1024, 1024); - - /* - * Shutdown the Bookie Servers and restart them using the same ledger - * directories. This will test the reading of pre-existing ledger index - * files in the LedgerCache during startup of a Bookie Server. - */ - restartBookies(); - - // Delete all of these ledgers from the BookKeeper client - for (LedgerHandle lh : lhs) { - bkc.deleteLedger(lh.getId()); - } - LOG.info("Finished deleting all ledgers so waiting for the GC thread to clean up the entryLogs"); - Thread.sleep(5000); - - /* - * Verify that the first two entry logs ([0,1].log) have been deleted - * from all of the Bookie Servers. When we restart the servers in this - * test, a new entry log is created. We know then that the first two - * entry logs should be deleted. - */ - for (File ledgerDirectory : bookieLedgerDirs()) { - assertFalse("Found the entry log file ([0,1].log) that should have been deleted in ledgerDirectory: " - + ledgerDirectory, TestUtils.hasLogFiles(ledgerDirectory, true, 0, 1)); - } - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LocalBookiesRegistryTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LocalBookiesRegistryTest.java deleted file mode 100644 index 36ff08b3853..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LocalBookiesRegistryTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.apache.bookkeeper.proto.LocalBookiesRegistry; -import org.junit.Test; - -/** - * Test the correctness and the availability outside of its package of LocalBookiesRegistryTest. - */ -public class LocalBookiesRegistryTest extends BookKeeperClusterTestCase { - - public LocalBookiesRegistryTest() { - super(1); - baseConf.setDisableServerSocketBind(true); - baseConf.setEnableLocalTransport(true); - } - - @Test - public void testAccessibleLocalBookiesRegistry() throws Exception { - assertEquals(1, bookieCount()); - bookieAddresses().forEach(a -> assertTrue(LocalBookiesRegistry.isLocalBookie(a))); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/MultipleThreadReadTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/MultipleThreadReadTest.java deleted file mode 100644 index dd451dc87a5..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/MultipleThreadReadTest.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.client.AsyncCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Multi-thread read test. - */ -public class MultipleThreadReadTest extends BookKeeperClusterTestCase { - private static final Logger LOG = LoggerFactory.getLogger(MultipleThreadReadTest.class); - - BookKeeper.DigestType digestType; - byte [] ledgerPassword = "aaa".getBytes(); - private int entriesPerLedger = 100; - final SyncObj mainSyncObj = new SyncObj(); - - class SyncObj { - volatile int counter; - boolean failed; - public SyncObj() { - counter = 0; - failed = false; - } - } - - BookKeeperTestClient readBkc; - - public MultipleThreadReadTest() { - super(6); - this.digestType = BookKeeper.DigestType.CRC32; - baseClientConf.setAddEntryTimeout(20); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - readBkc = new BookKeeperTestClient(baseClientConf); - } - - private Thread getWriterThread(final int tNo, final LedgerHandle lh, final AtomicBoolean resultHolder) { - Thread t = new Thread(new Runnable() { - @Override - public void run() { - final SyncObj tSync = new SyncObj(); - for (int j = 0; j < entriesPerLedger; j++) { - final byte[] entry = ("Entry-" + tNo + "-" + j).getBytes(); - lh.asyncAddEntry(entry, new AsyncCallback.AddCallback() { - @Override - public void addComplete(int rc, LedgerHandle ledgerHandle, long eid, Object o) { - SyncObj syncObj = (SyncObj) o; - synchronized (syncObj) { - if (rc != BKException.Code.OK) { - LOG.error("Add entry {} failed : rc = {}", new String(entry, UTF_8), rc); - syncObj.failed = true; - syncObj.notify(); - } else { - syncObj.counter++; - syncObj.notify(); - } - } - } - }, tSync); - } - synchronized (tSync) { - while (!tSync.failed && tSync.counter < entriesPerLedger) { - try { - tSync.wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - resultHolder.set(!tSync.failed); - } - // close this handle - try { - lh.close(); - } catch (InterruptedException ie) { - LOG.error("Interrupted on closing ledger handle {} : ", lh.getId(), ie); - Thread.currentThread().interrupt(); - } catch (BKException bke) { - LOG.error("Error on closing ledger handle {} : ", lh.getId(), bke); - } - } - }, "WriteThread(Lid=" + lh.getId() + ")"); - t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread thread, Throwable throwable) { - synchronized (mainSyncObj) { - mainSyncObj.failed = true; - } - } - }); - return t; - } - - private Thread getReaderThread(final int tNo, final LedgerHandle lh, final int ledgerNumber, - final AtomicBoolean resultHolder) { - Thread t = new Thread(new Runnable() { - @Override - public void run() { - //LedgerHandle lh = clientList.get(0).openLedger(ledgerIds.get(tNo % numLedgers), - // digestType, ledgerPassword); - long startEntryId = 0; - long endEntryId; - long eid = 0; - while (startEntryId <= entriesPerLedger - 1) { - endEntryId = Math.min(startEntryId + 10 - 1, entriesPerLedger - 1); - final long numEntries = (endEntryId - startEntryId) + 1; - boolean success = true; - try { - Enumeration list = lh.readEntries(startEntryId, endEntryId); - for (int j = 0; j < numEntries; j++) { - LedgerEntry e; - try { - e = list.nextElement(); - } catch (NoSuchElementException exception) { - success = false; - break; - } - long curEid = eid++; - if (e.getEntryId() != curEid) { - LOG.error("Expected entry id {} for ledger {} but {} found.", - curEid, lh.getId(), e.getEntryId()); - success = false; - break; - } - byte[] data = e.getEntry(); - if (!Arrays.equals(("Entry-" + ledgerNumber + "-" + e.getEntryId()).getBytes(), data)) { - LOG.error("Expected entry data 'Entry-{}-{}' but {} found for ledger {}.", - ledgerNumber, e.getEntryId(), new String(data, UTF_8), lh.getId()); - success = false; - break; - } - } - if (success) { - success = !list.hasMoreElements(); - if (!success) { - LOG.error("Found more entries returned on reading ({}-{}) from ledger {}.", - startEntryId, endEntryId, lh.getId()); - } - } - } catch (InterruptedException ie) { - LOG.error("Interrupted on reading entries ({} - {}) from ledger {} : ", - startEntryId, endEntryId, lh.getId(), ie); - Thread.currentThread().interrupt(); - success = false; - } catch (BKException bke) { - LOG.error("Failed on reading entries ({} - {}) from ledger {} : ", - startEntryId, endEntryId, lh.getId(), bke); - success = false; - } - resultHolder.set(success); - if (!success) { - break; - } - startEntryId = endEntryId + 1; - } - } - }, "ReadThread(Tid =" + tNo + ", Lid=" + lh.getId() + ")"); - t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread thread, Throwable throwable) { - LOG.error("Uncaught exception in thread {} : ", thread.getName(), throwable); - synchronized (mainSyncObj) { - mainSyncObj.failed = true; - } - } - }); - return t; - } - - /** - * Ledger L is handled threads [L, T+(T/L), T+2*(T/L) ... ] - * Reads are simultaneous, writes are sequential. - * @throws java.io.IOException - */ - public void multiLedgerMultiThreadRead(final int numLedgers, - final int numThreads) throws IOException { - assertTrue(numLedgers != 0 && numThreads >= numLedgers && numThreads % numLedgers == 0); - - // We create numThread/numLedger clients so that each client can be used to open a handle. - try { - final List oldLedgerHandles = new ArrayList(); - final List ledgerIds = new ArrayList(); - List threadList = new ArrayList(); - List writeResults = new ArrayList(); - // Start write threads. - // Only one thread writes to a ledger, so just use numLedgers instead. - for (int i = 0; i < numLedgers; i++) { - LedgerHandle lh = bkc.createLedger(digestType, ledgerPassword); - oldLedgerHandles.add(lh); - ledgerIds.add(lh.getId()); - AtomicBoolean writeResult = new AtomicBoolean(false); - writeResults.add(writeResult); - Thread t; - threadList.add(t = getWriterThread(i, oldLedgerHandles.get(i), writeResult)); - t.start(); - } - // Wait for the threads to complete - for (Thread t : threadList) { - t.join(); - } - synchronized (mainSyncObj) { - if (mainSyncObj.failed) { - fail("Test failed because we encountered uncaught exception on adding entries."); - } - } - for (int i = 0; i < numLedgers; i++) { - assertTrue("Failed on adding entries for ledger " + oldLedgerHandles.get(i).getId(), - writeResults.get(i).get()); - } - // Close the ledger handles. - for (LedgerHandle lh : oldLedgerHandles) { - try { - lh.close(); - } catch (BKException.BKLedgerClosedException e) { - } catch (Exception e) { - fail("Error while closing handle."); - } - } - // Now try to read. - mainSyncObj.failed = false; - threadList.clear(); - - List readResults = new ArrayList(); - for (int i = 0; i < numThreads; i++) { - AtomicBoolean readResult = new AtomicBoolean(false); - Thread t; - threadList.add(t = getReaderThread(i, readBkc.openLedger(ledgerIds.get(i % numLedgers), - digestType, ledgerPassword), i % numLedgers, readResult)); - readResults.add(readResult); - t.start(); - } - // Wait for the threads to complete. - for (Thread t : threadList) { - t.join(); - } - synchronized (mainSyncObj) { - if (mainSyncObj.failed) { - fail("Test failed because we encountered uncaught exception on reading entries"); - } - } - for (AtomicBoolean readResult : readResults) { - assertTrue("Failed on read entries", readResult.get()); - } - } catch (BKException e) { - LOG.error("Test failed", e); - fail("Test failed due to BookKeeper exception"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Test failed", e); - fail("Test failed due to interruption"); - } - } - - @Test - public void test10Ledgers20ThreadsRead() throws IOException { - multiLedgerMultiThreadRead(10, 20); - } - - @Test - public void test10Ledgers200ThreadsRead() throws IOException { - multiLedgerMultiThreadRead(10, 200); - } - - @Test - public void test1Ledger20ThreadsRead() throws IOException { - multiLedgerMultiThreadRead(1, 20); - } - - @Override - public void tearDown() throws Exception { - readBkc.close(); - super.tearDown(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/OpStatTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/OpStatTest.java deleted file mode 100644 index c5abdc521a5..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/OpStatTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.test; - -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.BOOKIE_SCOPE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.JOURNAL_FORCE_WRITE_QUEUE_SIZE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.JOURNAL_QUEUE_SIZE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.JOURNAL_SCOPE; -import static org.apache.bookkeeper.bookie.BookKeeperServerStats.SERVER_SCOPE; -import static org.junit.Assert.assertTrue; - -import java.util.function.BiConsumer; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.util.MathUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Basic tests to verify that stats are being updated as expected. - */ -public class OpStatTest extends BookKeeperClusterTestCase { - private LedgerHandle lh; - - public OpStatTest() { - super(1); - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - lh = bkc.createLedger(1, 1, BookKeeper.DigestType.CRC32, "".getBytes()); - resetBookieOpLoggers(); - } - - @After - @Override - public void tearDown() throws Exception { - lh.close(); - lh = null; - super.tearDown(); - } - - private void validateOpStat(TestStatsProvider stats, String path, BiConsumer f) { - assertTrue(stats != null); - TestStatsProvider.TestOpStatsLogger logger = stats.getOpStatsLogger(path); - assertTrue(logger != null); - f.accept(logger.getSuccessCount(), logger.getSuccessAverage()); - } - - private void validateOpStat(TestStatsProvider stats, String[] paths, BiConsumer f) { - for (String path : paths) { - validateOpStat(stats, path, f); - } - } - - private void validateNonMonotonicCounterGauge(TestStatsProvider stats, String path, BiConsumer f) { - assertTrue(stats != null); - TestStatsProvider.TestCounter counter = stats.getCounter(path); - assertTrue(counter != null); - f.accept(counter.get(), counter.getMax()); - } - - private void validateNonMonotonicCounterGauges(TestStatsProvider stats, String[] paths, BiConsumer f) { - for (String path : paths) { - validateNonMonotonicCounterGauge(stats, path, f); - } - } - - @Test - public void testTopLevelBookieWriteCounters() throws Exception { - long startNanos = MathUtils.nowInNano(); - lh.addEntry("test".getBytes()); - long elapsed = MathUtils.elapsedNanos(startNanos); - TestStatsProvider stats = getStatsProvider(0); - validateOpStat(stats, new String[]{ - SERVER_SCOPE + ".ADD_ENTRY", - SERVER_SCOPE + ".ADD_ENTRY_REQUEST", - SERVER_SCOPE + ".BookieWriteThreadPool.task_queued", - SERVER_SCOPE + ".BookieWriteThreadPool.task_execution", - SERVER_SCOPE + ".CHANNEL_WRITE" - }, (count, average) -> { - assertTrue(count == 1); - assertTrue(average > 0); - assertTrue(average <= elapsed); - }); - validateOpStat(stats, new String[]{ - SERVER_SCOPE + ".CHANNEL_WRITE" - }, (count, average) -> { - assertTrue(count > 0); - assertTrue(average > 0); - assertTrue(average <= elapsed); - }); - validateNonMonotonicCounterGauges(stats, new String[]{ - BOOKIE_SCOPE + "." + JOURNAL_SCOPE + ".journalIndex_0." + JOURNAL_FORCE_WRITE_QUEUE_SIZE, - BOOKIE_SCOPE + "." + JOURNAL_SCOPE + ".journalIndex_0." + JOURNAL_QUEUE_SIZE - }, (value, max) -> { - assertTrue(max > 0); - }); - } - - @Test - public void testTopLevelBookieReadCounters() throws Exception { - long startNanos = MathUtils.nowInNano(); - lh.addEntry("test".getBytes()); - lh.readEntries(0, 0); - long elapsed = MathUtils.elapsedNanos(startNanos); - TestStatsProvider stats = getStatsProvider(0); - validateOpStat(stats, new String[]{ - SERVER_SCOPE + ".READ_ENTRY", - SERVER_SCOPE + ".READ_ENTRY_REQUEST", - SERVER_SCOPE + ".BookieReadThreadPool.task_queued", - SERVER_SCOPE + ".BookieReadThreadPool.task_execution", - }, (count, average) -> { - assertTrue(count == 1); - assertTrue(average > 0); - assertTrue(average <= elapsed); - }); - validateOpStat(stats, new String[]{ - SERVER_SCOPE + ".CHANNEL_WRITE" - }, (count, average) -> { - assertTrue(count > 0); - assertTrue(average > 0); - assertTrue(average <= elapsed); - }); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java deleted file mode 100644 index d3aa1ed7ad2..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.File; -import java.util.Enumeration; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.util.PortManager; -import org.awaitility.Awaitility; -import org.junit.Test; - -/** - * Test to verify the readonly feature of bookies. - */ -public class ReadOnlyBookieTest extends BookKeeperClusterTestCase { - - public ReadOnlyBookieTest() { - super(2); - baseConf.setLedgerStorageClass(InterleavedLedgerStorage.class.getName()); - baseConf.setEntryLogFilePreAllocationEnabled(false); - baseConf.setMinUsableSizeForEntryLogCreation(Long.MAX_VALUE); - } - - /** - * Check readonly bookie. - */ - @Test - public void testBookieShouldServeAsReadOnly() throws Exception { - killBookie(0); - baseConf.setReadOnlyModeEnabled(true); - startNewBookie(); - LedgerHandle ledger = bkc.createLedger(2, 2, DigestType.MAC, - "".getBytes()); - - // Check new bookie with readonly mode enabled. - File[] ledgerDirs = confByIndex(1).getLedgerDirs(); - assertEquals("Only one ledger dir should be present", 1, - ledgerDirs.length); - Bookie bookie = serverByIndex(1).getBookie(); - LedgerDirsManager ledgerDirsManager = ((BookieImpl) bookie).getLedgerDirsManager(); - - for (int i = 0; i < 10; i++) { - ledger.addEntry("data".getBytes()); - } - - // Now add the current ledger dir to filled dirs list - ledgerDirsManager.addToFilledDirs(new File(ledgerDirs[0], "current")); - - try { - ledger.addEntry("data".getBytes()); - fail("Should fail to add entry since there isn't enough bookies alive."); - } catch (BKException.BKNotEnoughBookiesException e) { - // Expected - } - - assertTrue("Bookie should be running and converted to readonly mode", - bookie.isRunning() && bookie.isReadOnly()); - - // Now kill the other bookie and read entries from the readonly bookie - killBookie(0); - - Enumeration readEntries = ledger.readEntries(0, 9); - while (readEntries.hasMoreElements()) { - LedgerEntry entry = readEntries.nextElement(); - assertEquals("Entry should contain correct data", "data", - new String(entry.getEntry())); - } - } - - @Test - public void testBookieShouldTurnWritableFromReadOnly() throws Exception { - killBookie(0); - baseConf.setReadOnlyModeEnabled(true); - baseConf.setDiskCheckInterval(Integer.MAX_VALUE); - startNewBookie(); - LedgerHandle ledger = bkc.createLedger(2, 2, DigestType.MAC, - "".getBytes()); - - // Check new bookie with readonly mode enabled. - File[] ledgerDirs = confByIndex(1).getLedgerDirs(); - assertEquals("Only one ledger dir should be present", 1, - ledgerDirs.length); - BookieImpl bookie = (BookieImpl) serverByIndex(1).getBookie(); - LedgerDirsManager ledgerDirsManager = bookie.getLedgerDirsManager(); - - for (int i = 0; i < 10; i++) { - ledger.addEntry("data".getBytes()); - } - - File testDir = new File(ledgerDirs[0], "current"); - - // Now add the current ledger dir to filled dirs list - ledgerDirsManager.addToFilledDirs(testDir); - - try { - ledger.addEntry("data".getBytes()); - fail("Should fail to add entry since there isn't enough bookies alive."); - } catch (BKException.BKNotEnoughBookiesException e) { - // Expected - } - - // waitForReadOnlyBookie adds another listener thread to observe the node status of bookie, - // which may be out of sync with the triggering of node changes in EnsemblePlacementPolicy. - // This sequence leads to flaky test. So change from watching zk to Awaitility.await(). - Awaitility.await().untilAsserted(() -> { - assertTrue("Bookie should be running and converted to readonly mode", - bookie.isRunning() && bookie.isReadOnly()); - }); - LOG.info("bookie is running {}, readonly {}.", bookie.isRunning(), bookie.isReadOnly()); - - // should fail to create ledger - try { - bkc.createLedger(2, 2, DigestType.MAC, "".getBytes()); - fail("Should fail to create a ledger since there isn't enough bookies alive."); - } catch (BKException.BKNotEnoughBookiesException bke) { - // Expected. - } - - // Now add the current ledger dir back to writable dirs list - ledgerDirsManager.addToWritableDirs(testDir, true); - - // waitForWritableBookie adds another listener thread to observe the node status of bookie, - // which may be out of sync with the triggering of node changes in EnsemblePlacementPolicy. - // This sequence leads to flaky test. So change from watching zk to Awaitility.await(). - Awaitility.await().untilAsserted(() -> { - assertTrue("Bookie should be running and converted back to writable mode", bookie.isRunning() - && !bookie.isReadOnly()); - }); - LOG.info("bookie is running {}, readonly {}.", bookie.isRunning(), bookie.isReadOnly()); - - LedgerHandle newLedger = bkc.createLedger(2, 2, DigestType.MAC, "".getBytes()); - for (int i = 0; i < 10; i++) { - newLedger.addEntry("data".getBytes()); - } - Enumeration readEntries = newLedger.readEntries(0, 9); - while (readEntries.hasMoreElements()) { - LedgerEntry entry = readEntries.nextElement(); - assertEquals("Entry should contain correct data", "data", new String(entry.getEntry())); - } - } - - /** - * check readOnlyModeEnabled=false. - */ - @Test - public void testBookieShutdownIfReadOnlyModeNotEnabled() throws Exception { - killBookie(1); - baseConf.setReadOnlyModeEnabled(false); - startNewBookie(); - - File[] ledgerDirs = confByIndex(1).getLedgerDirs(); - assertEquals("Only one ledger dir should be present", 1, - ledgerDirs.length); - BookieImpl bookie = (BookieImpl) serverByIndex(1).getBookie(); - LedgerHandle ledger = bkc.createLedger(2, 2, DigestType.MAC, - "".getBytes()); - LedgerDirsManager ledgerDirsManager = bookie.getLedgerDirsManager(); - - for (int i = 0; i < 10; i++) { - ledger.addEntry("data".getBytes()); - } - - // Now add the current ledger dir to filled dirs list - ledgerDirsManager.addToFilledDirs(new File(ledgerDirs[0], "current")); - - try { - ledger.addEntry("data".getBytes()); - fail("Should fail to add entry since there isn't enough bookies alive."); - } catch (BKException.BKNotEnoughBookiesException e) { - // Expected - } - - // wait for up to 10 seconds for bookie to shut down - for (int i = 0; i < 10 && bookie.isAlive(); i++) { - Thread.sleep(1000); - } - assertFalse("Bookie should shutdown if readOnlyMode not enabled", - bookie.isAlive()); - } - - /** - * Check multiple ledger dirs. - */ - @Test - public void testBookieContinueWritingIfMultipleLedgersPresent() - throws Exception { - startNewBookieWithMultipleLedgerDirs(2); - - File[] ledgerDirs = confByIndex(1).getLedgerDirs(); - assertEquals("Only one ledger dir should be present", 2, - ledgerDirs.length); - BookieImpl bookie = (BookieImpl) serverByIndex(1).getBookie(); - LedgerHandle ledger = bkc.createLedger(2, 2, DigestType.MAC, - "".getBytes()); - LedgerDirsManager ledgerDirsManager = bookie.getLedgerDirsManager(); - - for (int i = 0; i < 10; i++) { - ledger.addEntry("data".getBytes()); - } - - // Now add the current ledger dir to filled dirs list - ledgerDirsManager.addToFilledDirs(new File(ledgerDirs[0], "current")); - for (int i = 0; i < 10; i++) { - ledger.addEntry("data".getBytes()); - } - assertEquals("writable dirs should have one dir", 1, ledgerDirsManager - .getWritableLedgerDirs().size()); - assertTrue("Bookie should shutdown if readOnlyMode not enabled", - bookie.isRunning()); - } - - private void startNewBookieWithMultipleLedgerDirs(int numOfLedgerDirs) - throws Exception { - ServerConfiguration conf = confByIndex(1); - killBookie(1); - - File[] ledgerDirs = new File[numOfLedgerDirs]; - for (int i = 0; i < numOfLedgerDirs; i++) { - File dir = tmpDirs.createNew("bookie", "test"); - ledgerDirs[i] = dir; - } - - ServerConfiguration newConf = newServerConfiguration( - PortManager.nextFreePort(), - ledgerDirs[0], ledgerDirs); - newConf.setDiskCheckInterval(Integer.MAX_VALUE); - startAndAddBookie(newConf); - } - - /** - * Test ledger creation with readonly bookies. - */ - @Test - public void testLedgerCreationShouldFailWithReadonlyBookie() throws Exception { - killBookie(1); - baseConf.setReadOnlyModeEnabled(true); - startNewBookie(); - - serverByIndex(1).getBookie().getStateManager().transitionToReadOnlyMode().get(); - try { - bkc.waitForReadOnlyBookie(BookieImpl.getBookieId(confByIndex(1))) - .get(30, TimeUnit.SECONDS); - - bkc.createLedger(2, 2, DigestType.CRC32, "".getBytes()); - fail("Must throw exception, as there is one readonly bookie"); - } catch (BKException e) { - // Expected - } - } - - /** - * Try to read closed ledger from restarted ReadOnlyBookie. - */ - public void testReadFromReadOnlyBookieShouldBeSuccess() throws Exception { - LedgerHandle ledger = bkc.createLedger(2, 2, DigestType.MAC, "".getBytes()); - for (int i = 0; i < 10; i++) { - ledger.addEntry("data".getBytes()); - } - ledger.close(); - confByIndex(1).setReadOnlyModeEnabled(true); - confByIndex(1).setDiskCheckInterval(500); - restartBookies(); - - // Check new bookie with readonly mode enabled. - File[] ledgerDirs = confByIndex(1).getLedgerDirs(); - assertEquals("Only one ledger dir should be present", 1, ledgerDirs.length); - BookieImpl bookie = (BookieImpl) serverByIndex(1).getBookie(); - LedgerDirsManager ledgerDirsManager = bookie.getLedgerDirsManager(); - - // Now add the current ledger dir to filled dirs list - ledgerDirsManager.addToFilledDirs(new File(ledgerDirs[0], "current")); - - // Wait till Bookie converts to ReadOnly mode. - Thread.sleep(1000); - assertTrue("Bookie should be converted to readonly mode", bookie.isRunning() && bookie.isReadOnly()); - - // Now kill the other bookie and read entries from the readonly bookie - killBookie(0); - - Enumeration readEntries = ledger.readEntries(0, 9); - while (readEntries.hasMoreElements()) { - LedgerEntry entry = readEntries.nextElement(); - assertEquals("Entry should contain correct data", "data", new String(entry.getEntry())); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TestCallbacks.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TestCallbacks.java deleted file mode 100644 index cdfdcd05b0e..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TestCallbacks.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import com.google.common.util.concurrent.AbstractFuture; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.LedgerHandle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Callbacks implemented with SettableFuture, to be used in tests. - */ -public class TestCallbacks { - - private static final Logger logger = LoggerFactory.getLogger(TestCallbacks.class); - - /** - * Add callback future implementation. - */ - public static class AddCallbackFuture - extends AbstractFuture implements AddCallback { - - private final long expectedEntryId; - - public AddCallbackFuture(long entryId) { - this.expectedEntryId = entryId; - } - - public long getExpectedEntryId() { - return expectedEntryId; - } - - @Override - public void addComplete(int rc, LedgerHandle lh, long entryId, Object ctx) { - logger.info("Add entry {} completed : entryId = {}, rc = {}", - expectedEntryId, entryId, rc); - if (rc != BKException.Code.OK) { - setException(BKException.create(rc)); - } else { - set(entryId); - } - } - } -} - diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TmpDirs.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TmpDirs.java deleted file mode 100644 index 7b8d23e2bd4..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TmpDirs.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import java.io.File; -import java.util.LinkedList; -import java.util.List; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.commons.io.FileUtils; - -/** - * Utility class for managing tmp directories in tests. - */ -public class TmpDirs { - private final List tmpDirs = new LinkedList<>(); // retained to delete files - - public File createNew(String prefix, String suffix) throws Exception { - File dir = IOUtils.createTempDir(prefix, suffix); - tmpDirs.add(dir); - return dir; - } - - public void cleanup() throws Exception { - for (File f : tmpDirs) { - FileUtils.deleteDirectory(f); - } - } - - public List getDirs() { - return tmpDirs; - } -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperCluster.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperCluster.java deleted file mode 100644 index 08ecbd7cc12..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperCluster.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.util.BookKeeperConstants.AVAILABLE_NODE; -import static org.apache.bookkeeper.util.BookKeeperConstants.INSTANCEID; -import static org.apache.bookkeeper.util.BookKeeperConstants.READONLY; - -import java.io.IOException; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.zookeeper.ZooKeeperWatcherBase; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.Transaction; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; - -/** - * Interface for ZooKeeperCluster. - */ -public interface ZooKeeperCluster { - ZooKeeper getZooKeeperClient(); - - String getZooKeeperConnectString(); - - String getMetadataServiceUri(); - - String getMetadataServiceUri(String zkLedgersRootPath); - - String getMetadataServiceUri(String zkLedgersRootPath, String type); - - void startCluster() throws Exception; - - void stopCluster() throws Exception; - - void restartCluster() throws Exception; - - void killCluster() throws Exception; - - void sleepCluster(int time, TimeUnit timeUnit, CountDownLatch l) - throws InterruptedException, IOException; - - default void expireSession(ZooKeeper zk) throws Exception { - long id = zk.getSessionId(); - byte[] password = zk.getSessionPasswd(); - ZooKeeperWatcherBase w = new ZooKeeperWatcherBase(10000); - ZooKeeper zk2 = new ZooKeeper(getZooKeeperConnectString(), zk.getSessionTimeout(), w, id, password); - w.waitForConnection(); - zk2.close(); - } - - default void createBKEnsemble(String ledgersPath) throws KeeperException, InterruptedException { - Transaction txn = getZooKeeperClient().transaction(); - txn.create(ledgersPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - txn.create(ledgersPath + "/" + AVAILABLE_NODE, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - txn.create(ledgersPath + "/" + AVAILABLE_NODE + "/" + READONLY, new byte[0], Ids.OPEN_ACL_UNSAFE, - CreateMode.PERSISTENT); - String instanceId = UUID.randomUUID().toString(); - txn.create(ledgersPath + "/" + INSTANCEID, instanceId.getBytes(UTF_8), - Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - txn.commit(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperClusterUtil.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperClusterUtil.java deleted file mode 100644 index 3eace4a62c5..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperClusterUtil.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.test; - -import java.io.IOException; -import java.nio.file.Files; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.meta.LongHierarchicalLedgerManagerFactory; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.test.QuorumUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Provides multi node zookeeper cluster. - */ -@Slf4j -public class ZooKeeperClusterUtil implements ZooKeeperCluster { - - static { - enableZookeeperTestEnvVariables(); - } - - static final Logger LOG = LoggerFactory.getLogger(ZooKeeperClusterUtil.class); - private final int numOfZKNodes; - public QuorumUtil quorumUtil; - String connectString; - protected ZooKeeper zkc; // zookeeper client - - public static void enableZookeeperTestEnvVariables() { - /* - * org.apache.zookeeper.test.ClientBase uses FourLetterWordMain, from - * 3.5.3 four letter words are disabled by default due to security - * reasons - */ - System.setProperty("zookeeper.4lw.commands.whitelist", "*"); - System.setProperty("zookeeper.admin.enableServer", "false"); - try { - System.setProperty("build.test.dir", Files.createTempDirectory("zktests").toFile().getCanonicalPath()); - } catch (IOException e) { - log.error("Failed to create temp dir, so setting build.test.dir system property to /tmp"); - System.setProperty("build.test.dir", "/tmp"); - } - } - - public ZooKeeperClusterUtil(int numOfZKNodes) throws IOException, KeeperException, InterruptedException { - if ((numOfZKNodes < 3) || (numOfZKNodes % 2 == 0)) { - throw new IllegalArgumentException("numOfZKNodes should be atleast 3 and it should not be even number"); - } - this.numOfZKNodes = numOfZKNodes; - } - - @Override - public String getZooKeeperConnectString() { - return connectString; - } - - @Override - public String getMetadataServiceUri() { - return getMetadataServiceUri("/ledgers"); - } - - @Override - public String getMetadataServiceUri(String zkLedgersRootPath) { - return getMetadataServiceUri(zkLedgersRootPath, LongHierarchicalLedgerManagerFactory.NAME); - } - - @Override - public String getMetadataServiceUri(String zkLedgersRootPath, String type) { - /* - * URI doesn't accept ',', for more info. check - * AbstractConfiguration.getMetadataServiceUri() - */ - return "zk+" + type + "://" + connectString.replace(",", ";") + zkLedgersRootPath; - } - - @Override - public ZooKeeper getZooKeeperClient() { - return zkc; - } - - @Override - public void startCluster() throws Exception { - // QuorumUtil will start 2*n+1 nodes. - quorumUtil = new QuorumUtil(numOfZKNodes / 2); - quorumUtil.startAll(); - connectString = quorumUtil.getConnString(); - // create a zookeeper client - if (LOG.isDebugEnabled()) { - LOG.debug("Instantiate ZK Client"); - } - zkc = ZooKeeperClient.newBuilder().connectString(getZooKeeperConnectString()).sessionTimeoutMs(10000).build(); - - // create default bk ensemble - createBKEnsemble("/ledgers"); - } - - @Override - public void stopCluster() throws Exception { - if (zkc != null) { - zkc.close(); - } - quorumUtil.shutdownAll(); - } - - @Override - public void restartCluster() throws Exception { - quorumUtil.startAll(); - } - - @Override - public void killCluster() throws Exception { - quorumUtil.tearDown(); - } - - @Override - public void sleepCluster(int time, TimeUnit timeUnit, CountDownLatch l) throws InterruptedException, IOException { - throw new UnsupportedOperationException("sleepServer operation is not supported for ZooKeeperClusterUtil"); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperUtil.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperUtil.java deleted file mode 100644 index dcaa0506afe..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperUtil.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.test; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.apache.commons.io.FileUtils; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.server.NIOServerCnxnFactory; -import org.apache.zookeeper.server.ZooKeeperServer; -import org.apache.zookeeper.test.ClientBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the zookeeper utilities. - */ -public class ZooKeeperUtil implements ZooKeeperCluster { - - static { - // org.apache.zookeeper.test.ClientBase uses FourLetterWordMain, from 3.5.3 four letter words - // are disabled by default due to security reasons - System.setProperty("zookeeper.4lw.commands.whitelist", "*"); - } - static final Logger LOG = LoggerFactory.getLogger(ZooKeeperUtil.class); - - // ZooKeeper related variables - protected Integer zooKeeperPort = 0; - private InetSocketAddress zkaddr; - - protected ZooKeeperServer zks; - protected ZooKeeper zkc; // zookeeper client - protected NIOServerCnxnFactory serverFactory; - protected File zkTmpDir; - private String connectString; - - public ZooKeeperUtil() { - String loopbackIPAddr = InetAddress.getLoopbackAddress().getHostAddress(); - zkaddr = new InetSocketAddress(loopbackIPAddr, 0); - connectString = loopbackIPAddr + ":" + zooKeeperPort; - } - - @Override - public ZooKeeper getZooKeeperClient() { - return zkc; - } - - @Override - public String getZooKeeperConnectString() { - return connectString; - } - - @Override - public String getMetadataServiceUri() { - return getMetadataServiceUri("/ledgers"); - } - - @Override - public String getMetadataServiceUri(String zkLedgersRootPath) { - return "zk://" + connectString + zkLedgersRootPath; - } - - @Override - public String getMetadataServiceUri(String zkLedgersRootPath, String type) { - return "zk+" + type + "://" + connectString + zkLedgersRootPath; - } - - @Override - public void startCluster() throws Exception { - // create a ZooKeeper server(dataDir, dataLogDir, port) - if (LOG.isDebugEnabled()) { - LOG.debug("Running ZK server"); - } - ClientBase.setupTestEnv(); - zkTmpDir = IOUtils.createTempDir("zookeeper", "test"); - - // start the server and client. - restartCluster(); - - // create default bk ensemble - createBKEnsemble("/ledgers"); - } - - @Override - public void restartCluster() throws Exception { - zks = new ZooKeeperServer(zkTmpDir, zkTmpDir, - ZooKeeperServer.DEFAULT_TICK_TIME); - serverFactory = new NIOServerCnxnFactory(); - serverFactory.configure(zkaddr, 100); - serverFactory.startup(zks); - - if (0 == zooKeeperPort) { - zooKeeperPort = serverFactory.getLocalPort(); - zkaddr = new InetSocketAddress(zkaddr.getHostName(), zooKeeperPort); - connectString = zkaddr.getHostName() + ":" + zooKeeperPort; - } - - boolean b = ClientBase.waitForServerUp(getZooKeeperConnectString(), - ClientBase.CONNECTION_TIMEOUT); - if (LOG.isDebugEnabled()) { - LOG.debug("Server up: " + b); - } - - // create a zookeeper client - if (LOG.isDebugEnabled()) { - LOG.debug("Instantiate ZK Client"); - } - zkc = ZooKeeperClient.newBuilder() - .connectString(getZooKeeperConnectString()) - .sessionTimeoutMs(10000) - .build(); - } - - @Override - public void sleepCluster(final int time, - final TimeUnit timeUnit, - final CountDownLatch l) - throws InterruptedException, IOException { - Thread[] allthreads = new Thread[Thread.activeCount()]; - Thread.enumerate(allthreads); - for (final Thread t : allthreads) { - if (t.getName().contains("SyncThread:0")) { - Thread sleeper = new Thread() { - @SuppressWarnings("deprecation") - public void run() { - try { - t.suspend(); - l.countDown(); - timeUnit.sleep(time); - t.resume(); - } catch (Exception e) { - LOG.error("Error suspending thread", e); - } - } - }; - sleeper.start(); - return; - } - } - throw new IOException("ZooKeeper thread not found"); - } - - @Override - public void stopCluster() throws Exception { - if (zkc != null) { - zkc.close(); - } - - // shutdown ZK server - if (serverFactory != null) { - serverFactory.shutdown(); - assertTrue("waiting for server down", - ClientBase.waitForServerDown(getZooKeeperConnectString(), - ClientBase.CONNECTION_TIMEOUT)); - } - if (zks != null) { - zks.getTxnLogFactory().close(); - } - } - - @Override - public void killCluster() throws Exception { - stopCluster(); - FileUtils.deleteDirectory(zkTmpDir); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestBookieAuthZFactory.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestBookieAuthZFactory.java deleted file mode 100644 index 2cd0a80b324..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestBookieAuthZFactory.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tls; - -import static org.junit.Assert.fail; - -import java.io.IOException; -import org.apache.bookkeeper.auth.BookieAuthProvider; -import org.apache.bookkeeper.common.util.ReflectionUtils; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Light weight Unit Tests for BookieAuthZFactory. - */ -public class TestBookieAuthZFactory { - private static final Logger LOG = LoggerFactory.getLogger(TestBookieAuthZFactory.class); - - public TestBookieAuthZFactory() { - } - - /** - * Initialize a BookieAuthZFactory without configuring authorizedRoles in ServerConfiguration. - * This should fail as in order to use this authorization provider, we need to have authorizedRoles set. - */ - @Test - public void testBookieAuthZInitNoRoles() { - ServerConfiguration conf = new ServerConfiguration(); - String factoryClassName = BookieAuthZFactory.class.getName(); - BookieAuthProvider.Factory factory = ReflectionUtils.newInstance(factoryClassName, - BookieAuthProvider.Factory.class); - - try { - factory.init(conf); - fail("Not supposed to initialize BookieAuthZFactory without authorized roles set"); - } catch (IOException | RuntimeException e) { - LOG.info("BookieAuthZFactory did not initialize as there are no authorized roles set."); - } - } - - /** - * Initialize a BookieAuthZFactory as an authProvider and configure an empty string in authorizedRoles. - * This should fail as in order to use this as an authorization provider, we need to have valid authorizedRoles set. - */ - @Test - public void testBookieAuthZInitEmptyRole() { - ServerConfiguration conf = new ServerConfiguration(); - conf.setAuthorizedRoles(""); - String factoryClassName = BookieAuthZFactory.class.getName(); - BookieAuthProvider.Factory factory = ReflectionUtils.newInstance(factoryClassName, - BookieAuthProvider.Factory.class); - - try { - factory.init(conf); - fail("Not supposed to initialize BookieAuthZFactory without authorized roles set"); - } catch (IOException | RuntimeException e) { - LOG.info("BookieAuthZFactory did not initialize as there are no authorized roles set."); - } - } - - /** - * Initialize a BookieAuthZFactory with a valid string for the configured role. - * However, pass a null (or faulty) connection for it to authorize, it should fail. - */ - @Test - public void testBookieAuthZNewProviderNullAddress() { - ServerConfiguration conf = new ServerConfiguration(); - conf.setAuthorizedRoles("testRole"); - String factoryClassName = BookieAuthZFactory.class.getName(); - BookieAuthProvider.Factory factory = ReflectionUtils.newInstance(factoryClassName, - BookieAuthProvider.Factory.class); - - try { - factory.init(conf); - BookieAuthProvider authProvider = factory.newProvider(null, null); - authProvider.onProtocolUpgrade(); - fail("BookieAuthZFactory should fail with a null connection"); - } catch (IOException | RuntimeException e) { - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java deleted file mode 100644 index b5719deea0d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tls; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeTrue; - -import java.io.File; -import java.io.IOException; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.auth.AuthCallbacks; -import org.apache.bookkeeper.auth.AuthToken; -import org.apache.bookkeeper.auth.BookieAuthProvider; -import org.apache.bookkeeper.auth.ClientAuthProvider; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.BookKeeperClientStats; -import org.apache.bookkeeper.client.BookKeeperTestClient; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieConnectionPeer; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.proto.ClientConnectionPeer; -import org.apache.bookkeeper.proto.TestPerChannelBookieClient; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.tls.TLSContextFactory.KeyStoreType; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.bookkeeper.util.TestUtils; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests with TLS enabled. - */ -@RunWith(Parameterized.class) -public class TestTLS extends BookKeeperClusterTestCase { - - private static final Logger LOG = LoggerFactory.getLogger(TestPerChannelBookieClient.class); - - private static boolean secureClientSideChannel = false; - private static Collection secureClientSideChannelPrincipals = null; - - private static boolean secureBookieSideChannel = false; - private static Collection secureBookieSideChannelPrincipals = null; - - private KeyStoreType clientKeyStoreFormat; - private KeyStoreType clientTrustStoreFormat; - private KeyStoreType serverKeyStoreFormat; - private KeyStoreType serverTrustStoreFormat; - private final boolean useV2Protocol; - - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { - { "JKS", "JKS", false }, - { "PEM", "PEM", false }, - { "PEM", "PEM", true }, - { "PKCS12", "PKCS12", false }, - { "JKS", "PEM", false }, - { "PEM", "PKCS12", false }, - { "PKCS12", "JKS", false } - }); - } - public TestTLS(String keyStoreFormat, - String trustStoreFormat, - boolean useV2Protocol) { - super(3); - this.clientKeyStoreFormat = KeyStoreType.valueOf(keyStoreFormat); - this.clientTrustStoreFormat = KeyStoreType.valueOf(trustStoreFormat); - this.serverKeyStoreFormat = KeyStoreType.valueOf(keyStoreFormat); - this.serverTrustStoreFormat = KeyStoreType.valueOf(trustStoreFormat); - this.useV2Protocol = useV2Protocol; - } - - private String getResourcePath(String resource) throws Exception { - return this.getClass().getClassLoader().getResource(resource).toURI().getPath(); - } - - @Before - @Override - public void setUp() throws Exception { - /* client configuration */ - baseClientConf.setTLSProviderFactoryClass(TLSContextFactory.class.getName()); - baseClientConf.setTLSClientAuthentication(true); - baseClientConf.setUseV2WireProtocol(useV2Protocol); - baseClientConf.setLimitStatsLogging(false); - - switch (clientKeyStoreFormat) { - case PEM: - baseClientConf.setTLSKeyStoreType("PEM"); - baseClientConf.setTLSKeyStore(getResourcePath("client-key.pem")); - baseClientConf.setTLSCertificatePath(getResourcePath("client-cert.pem")); - - break; - case JKS: - baseClientConf.setTLSKeyStoreType("JKS"); - baseClientConf.setTLSKeyStore(getResourcePath("client-key.jks")); - baseClientConf.setTLSKeyStorePasswordPath(getResourcePath("keyStoreClientPassword.txt")); - - break; - case PKCS12: - baseClientConf.setTLSKeyStoreType("PKCS12"); - baseClientConf.setTLSKeyStore(getResourcePath("client-key.p12")); - baseClientConf.setTLSKeyStorePasswordPath(getResourcePath("keyStoreClientPassword.txt")); - - break; - default: - throw new Exception("Invalid client keystore format" + clientKeyStoreFormat); - } - - switch (clientTrustStoreFormat) { - case PEM: - baseClientConf.setTLSTrustStoreType("PEM"); - baseClientConf.setTLSTrustStore(getResourcePath("server-cert.pem")); - - break; - case JKS: - baseClientConf.setTLSTrustStoreType("JKS"); - baseClientConf.setTLSTrustStore(getResourcePath("server-key.jks")); - baseClientConf.setTLSTrustStorePasswordPath(getResourcePath("keyStoreServerPassword.txt")); - - break; - case PKCS12: - baseClientConf.setTLSTrustStoreType("PKCS12"); - baseClientConf.setTLSTrustStore(getResourcePath("server-key.p12")); - baseClientConf.setTLSTrustStorePasswordPath(getResourcePath("keyStoreServerPassword.txt")); - - break; - default: - throw new Exception("Invalid client keystore format" + clientTrustStoreFormat); - } - - /* server configuration */ - baseConf.setTLSProviderFactoryClass(TLSContextFactory.class.getName()); - baseConf.setTLSClientAuthentication(true); - - switch (serverKeyStoreFormat) { - case PEM: - baseConf.setTLSKeyStoreType("PEM"); - baseConf.setTLSKeyStore(getResourcePath("server-key.pem")); - baseConf.setTLSCertificatePath(getResourcePath("server-cert.pem")); - - break; - case JKS: - baseConf.setTLSKeyStoreType("JKS"); - baseConf.setTLSKeyStore(getResourcePath("server-key.jks")); - baseConf.setTLSKeyStorePasswordPath(getResourcePath("keyStoreServerPassword.txt")); - - break; - case PKCS12: - baseConf.setTLSKeyStoreType("PKCS12"); - baseConf.setTLSKeyStore(getResourcePath("server-key.p12")); - baseConf.setTLSKeyStorePasswordPath(getResourcePath("keyStoreServerPassword.txt")); - - break; - default: - throw new Exception("Invalid server keystore format" + serverKeyStoreFormat); - } - - switch (serverTrustStoreFormat) { - case PEM: - baseConf.setTLSTrustStoreType("PEM"); - baseConf.setTLSTrustStore(getResourcePath("client-cert.pem")); - - break; - case JKS: - baseConf.setTLSTrustStoreType("JKS"); - baseConf.setTLSTrustStore(getResourcePath("client-key.jks")); - baseConf.setTLSTrustStorePasswordPath(getResourcePath("keyStoreClientPassword.txt")); - - break; - - case PKCS12: - baseConf.setTLSTrustStoreType("PKCS12"); - baseConf.setTLSTrustStore(getResourcePath("client-key.p12")); - baseConf.setTLSTrustStorePasswordPath(getResourcePath("keyStoreClientPassword.txt")); - - break; - default: - throw new Exception("Invalid server keystore format" + serverTrustStoreFormat); - } - - super.setUp(); - } - - @After - @Override - public void tearDown() throws Exception { - super.tearDown(); - } - - /** - * Verify the BouncyCastleProvider Name is expected. - */ - @Test - public void testGetBouncyCastleProviderName() throws Exception { - String bcName = TLSContextFactory.getProvider().getName(); - Assert.assertEquals(bcName, TLSContextFactory.BC_FIPS); - } - - /** - * Verify that a server will not start if tls is enabled but no cert is specified. - */ - @Test - public void testStartTLSServerNoKeyStore() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration().setTLSKeyStore(null); - - try { - startAndAddBookie(bookieConf); - fail("Shouldn't have been able to start"); - } catch (SecurityException se) { - assertTrue(true); - } - } - - /** - * Verify handshake failure with a bad cert. - */ - @Test - public void testKeyMismatchFailure() throws Exception { - // Valid test case only for PEM format keys - assumeTrue(serverKeyStoreFormat == KeyStoreType.PEM); - - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - - // restart a bookie with bad cert - int restartBookieIdx = 0; - ServerConfiguration bookieConf = confByIndex(restartBookieIdx) - .setTLSCertificatePath(getResourcePath("client-cert.pem")); - killBookie(restartBookieIdx); - LOG.info("Sleeping for 1s before restarting bookie with bad cert"); - Thread.sleep(1000); - startAndAddBookie(bookieConf); - - // Create ledger and write entries - BookKeeper client = new BookKeeper(clientConf); - byte[] passwd = "testPassword".getBytes(); - int numEntries = 2; - byte[] testEntry = "testEntry".getBytes(); - - try (LedgerHandle lh = client.createLedger(numBookies, numBookies, DigestType.CRC32, passwd)) { - for (int i = 0; i <= numEntries; i++) { - lh.addEntry(testEntry); - } - fail("Should have failed with not enough bookies to write"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // expected - } - } - - /** - * Verify that a server will not start if ssl is enabled but the cert password is incorrect. - */ - @Test - public void testStartTLSServerBadPassword() throws Exception { - ServerConfiguration bookieConf = newServerConfiguration().setTLSKeyStorePasswordPath("badpassword"); - try { - startAndAddBookie(bookieConf); - fail("Shouldn't have been able to start"); - } catch (SecurityException se) { - assertTrue(true); - } - } - - private LedgerMetadata testClient(BookKeeper client, int clusterSize) throws Exception { - byte[] passwd = "testPassword".getBytes(); - int numEntries = 100; - long lid; - byte[] testEntry = "testEntry".getBytes(); - try (LedgerHandle lh = client.createLedger(clusterSize, clusterSize, DigestType.CRC32, passwd)) { - for (int i = 0; i <= numEntries; i++) { - lh.addEntry(testEntry); - } - lid = lh.getId(); - } - try (LedgerHandle lh = client.openLedger(lid, DigestType.CRC32, passwd)) { - Enumeration entries = lh.readEntries(0, numEntries); - while (entries.hasMoreElements()) { - LedgerEntry e = entries.nextElement(); - assertTrue("Entry contents incorrect", Arrays.equals(e.getEntry(), testEntry)); - } - BookKeeperAdmin admin = new BookKeeperAdmin(client, baseClientConf); - return admin.getLedgerMetadata(lh); - } - } - - private LedgerMetadata testClient(ClientConfiguration conf, int clusterSize) throws Exception { - try (BookKeeper client = new BookKeeper(conf)) { - return testClient(client, clusterSize); - } - } - - /** - * Verify the basic use of TLS. TLS client, TLS servers. - */ - @Test - public void testConnectToTLSClusterTLSClient() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - testClient(clientConf, numBookies); - } - - /** - * Verify the basic use of TLS. TLS client, TLS servers with LocalTransport. - */ - @Test - public void testConnectToLocalTLSClusterTLSClient() throws Exception { - // skip test - if (useV2Protocol) { - return; - } - - restartBookies(c -> { - c.setDisableServerSocketBind(true); - c.setEnableLocalTransport(true); - return c; - }); - - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - testClient(clientConf, numBookies); - } - - /** - * Verify Bookie refreshes certs at configured duration. - */ - @Test - public void testRefreshDurationForBookieCerts() throws Exception { - assumeTrue(serverKeyStoreFormat == KeyStoreType.PEM); - String originalTlsKeyFilePath = confByIndex(0).getTLSKeyStore(); - String invalidServerKey = getResourcePath("client-key.pem"); - File originalTlsCertFile = new File(originalTlsKeyFilePath); - File newTlsKeyFile = IOUtils.createTempFileAndDeleteOnExit(originalTlsKeyFilePath, "refresh"); - // clean up temp file even if test fails - newTlsKeyFile.deleteOnExit(); - File invalidServerKeyFile = new File(invalidServerKey); - // copy invalid cert to new temp file - FileUtils.copyFile(invalidServerKeyFile, newTlsKeyFile); - long refreshDurationInSec = 1; - restartBookies(c -> { - c.setTLSCertFilesRefreshDurationSeconds(1); - c.setTLSKeyStore(newTlsKeyFile.getAbsolutePath()); - return c; - }); - - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - try { - testClient(clientConf, numBookies); - Assert.fail("Should have fail due to invalid cert"); - } catch (Exception e) { - // Ok. - } - - // Sleep so, cert file can be refreshed - Thread.sleep(refreshDurationInSec * 1000 + 1000); - - // copy valid key-file at given new location - FileUtils.copyFile(originalTlsCertFile, newTlsKeyFile); - newTlsKeyFile.setLastModified(System.currentTimeMillis() + 1000); - // client should be successfully able to add entries over tls - testClient(clientConf, numBookies); - newTlsKeyFile.delete(); - } - - /** - * Verify Bookkeeper-client refreshes certs at configured duration. - */ - @Test - public void testRefreshDurationForBookkeeperClientCerts() throws Exception { - assumeTrue(serverKeyStoreFormat == KeyStoreType.PEM); - - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - String originalTlsCertFilePath = baseClientConf.getTLSCertificatePath(); - String invalidClientCert = getResourcePath("server-cert.pem"); - File originalTlsCertFile = new File(originalTlsCertFilePath); - File newTlsCertFile = IOUtils.createTempFileAndDeleteOnExit(originalTlsCertFilePath, "refresh"); - // clean up temp file even if test fails - newTlsCertFile.deleteOnExit(); - File invalidClientCertFile = new File(invalidClientCert); - // copy invalid cert to new temp file - FileUtils.copyFile(invalidClientCertFile, newTlsCertFile); - long refreshDurationInSec = 2; - clientConf.setTLSCertFilesRefreshDurationSeconds(1); - clientConf.setTLSCertificatePath(newTlsCertFile.getAbsolutePath()); - - // create a bookkeeper-client - try (BookKeeper client = new BookKeeper(clientConf)) { - byte[] testEntry = "testEntry".getBytes(); - byte[] passwd = "testPassword".getBytes(); - int totalAddEntries = 1; - CountDownLatch latch = new CountDownLatch(totalAddEntries); - AtomicInteger result = new AtomicInteger(-1); - LedgerHandle lh = client.createLedger(1, 1, DigestType.CRC32, passwd); - - for (int i = 0; i <= totalAddEntries; i++) { - lh.asyncAddEntry(testEntry, (rc, lgh, entryId, ctx) -> { - result.set(rc); - latch.countDown(); - }, null); - } - latch.await(1, TimeUnit.SECONDS); - Assert.assertNotEquals(result.get(), BKException.Code.OK); - - // Sleep so, cert file can be refreshed - Thread.sleep(refreshDurationInSec * 1000 + 1000); - - // copy valid key-file at given new location - FileUtils.copyFile(originalTlsCertFile, newTlsCertFile); - newTlsCertFile.setLastModified(System.currentTimeMillis() + 1000); - // client should be successfully able to add entries over tls - CountDownLatch latchWithValidCert = new CountDownLatch(totalAddEntries); - AtomicInteger validCertResult = new AtomicInteger(-1); - lh = client.createLedger(1, 1, DigestType.CRC32, passwd); - for (int i = 0; i <= totalAddEntries; i++) { - lh.asyncAddEntry(testEntry, (rc, lgh, entryId, ctx) -> { - validCertResult.set(rc); - latchWithValidCert.countDown(); - }, null); - } - latchWithValidCert.await(1, TimeUnit.SECONDS); - Assert.assertEquals(validCertResult.get(), BKException.Code.OK); - newTlsCertFile.delete(); - } - } - - /** - * Multiple clients, some with TLS, and some without TLS. - */ - @Test - public void testConnectToTLSClusterMixedClient() throws Exception { - ClientConfiguration confWithTLS = new ClientConfiguration(baseClientConf); - testClient(confWithTLS, numBookies); - - ClientConfiguration confNoTLS = new ClientConfiguration(baseClientConf); - confNoTLS.setTLSProviderFactoryClass(null); - testClient(confNoTLS, numBookies); - } - - /** - * Verify the basic use of TLS. TLS client, TLS servers. No Mutual Authentication. - */ - @Test - public void testConnectToTLSClusterTLSClientWithTLSNoAuthentication() throws Exception { - restartBookies(c -> { - c.setTLSClientAuthentication(false); - return c; - }); - - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - testClient(conf, numBookies); - } - - /** - * Verify the basic use of TLS. TLS client, TLS servers with mutual Auth. - */ - @Test - public void testConnectToTLSClusterTLSClientWithAuthentication() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - try { - testClient(conf, numBookies); - } catch (BKException.BKNotEnoughBookiesException nnbe) { - fail("Client should be able to connect to bookie"); - } - } - - /** - * Verify that a client without tls enabled can connect to a cluster with TLS. - */ - @Test - public void testConnectToTLSClusterNonTLSClient() throws Exception { - ClientConfiguration conf = new ClientConfiguration(baseClientConf); - conf.setTLSProviderFactoryClass(null); - try { - testClient(conf, numBookies); - } catch (BKException.BKNotEnoughBookiesException nnbe) { - fail("non tls client should be able to connect to tls enabled bookies"); - } - } - - /** - * Verify that a client will fail to connect to a server if it has asked for TLS, but it is not available. - */ - @Test - public void testClientWantsTLSNoServersHaveIt() throws Exception { - restartBookies(c -> { - c.setTLSProviderFactoryClass(null); - return c; - }); - - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - try { - testClient(clientConf, numBookies); - fail("Shouldn't be able to connect"); - } catch (BKException.BKNotEnoughBookiesException nnbe) { - // correct response - } - } - - /** - * Verify that a client will be able to connect to a bookie cluster if it has asked for TLS, and there are enough - * bookies with TLS enabled in the cluster, although few bookies do not have TLS enabled. - */ - @Test - public void testTLSClientButOnlyFewTLSServers() throws Exception { - // disable TLS on initial set of bookies - restartBookies(c -> { - c.setTLSProviderFactoryClass(null); - return c; - }); - - // add two bookies which support TLS - baseConf.setTLSProviderFactoryClass(TLSContextFactory.class.getName()); - - Set tlsBookiePorts = new HashSet<>(); - tlsBookiePorts.add(startNewBookie()); - tlsBookiePorts.add(startNewBookie()); - - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - LedgerMetadata metadata = testClient(clientConf, 2); - assertTrue(metadata.getAllEnsembles().size() > 0); - Collection> ensembles = metadata.getAllEnsembles().values(); - try (BookKeeper client = new BookKeeper(clientConf)) { - for (List bookies : ensembles) { - for (BookieId bookieAddress : bookies) { - int port = client.getBookieAddressResolver().resolve(bookieAddress).getPort(); - assertTrue(tlsBookiePorts.contains(port)); - } - } - } - } - - /** - * Verify that a client-side Auth plugin can access server certificates. - */ - @Test - public void testClientAuthPlugin() throws Exception { - secureClientSideChannel = false; - secureClientSideChannelPrincipals = null; - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - - clientConf.setClientAuthProviderFactoryClass(AllowOnlyBookiesWithX509Certificates.class.getName()); - - testClient(clientConf, numBookies); - assertTrue(secureClientSideChannel); - assertNotNull(secureClientSideChannelPrincipals); - assertTrue(!secureClientSideChannelPrincipals.isEmpty()); - assertTrue(secureClientSideChannelPrincipals.iterator().next() instanceof Certificate); - Certificate cert = (Certificate) secureClientSideChannelPrincipals.iterator().next(); - assertTrue(cert instanceof X509Certificate); - } - - /** - * Verify that a bookie-side Auth plugin can access server certificates. - */ - @Test - public void testBookieAuthPluginRequireClientTLSAuthentication() throws Exception { - restartBookies(c -> { - c.setBookieAuthProviderFactoryClass( - AllowOnlyClientsWithX509Certificates.class.getName()); - return c; - }); - - secureBookieSideChannel = false; - secureBookieSideChannelPrincipals = null; - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - - testClient(clientConf, numBookies); - assertTrue(secureBookieSideChannel); - assertNotNull(secureBookieSideChannelPrincipals); - assertTrue(!secureBookieSideChannelPrincipals.isEmpty()); - assertTrue(secureBookieSideChannelPrincipals.iterator().next() instanceof Certificate); - Certificate cert = (Certificate) secureBookieSideChannelPrincipals.iterator().next(); - assertTrue(cert instanceof X509Certificate); - } - - /** - * Verify that a bookie-side Auth plugin can access server certificates over LocalTransport. - */ - @Test - public void testBookieAuthPluginRequireClientTLSAuthenticationLocal() throws Exception { - if (useV2Protocol) { - return; - } - - restartBookies(c -> { - c.setBookieAuthProviderFactoryClass( - AllowOnlyClientsWithX509Certificates.class.getName()); - c.setDisableServerSocketBind(true); - c.setEnableLocalTransport(true); - return c; - }); - - secureBookieSideChannel = false; - secureBookieSideChannelPrincipals = null; - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - - testClient(clientConf, numBookies); - assertTrue(secureBookieSideChannel); - assertNotNull(secureBookieSideChannelPrincipals); - assertTrue(!secureBookieSideChannelPrincipals.isEmpty()); - assertTrue(secureBookieSideChannelPrincipals.iterator().next() instanceof Certificate); - Certificate cert = (Certificate) secureBookieSideChannelPrincipals.iterator().next(); - assertTrue(cert instanceof X509Certificate); - } - - /** - * Verify that given role in client certificate is checked when BookieAuthZFactory is set. - * Positive test case where all given roles are present. - * If authorization fails unexpectedly, we catch the UnauthorizedAccessException and fail. - * Otherwise we exit the test and mark it as success - */ - @Test - public void testRoleBasedAuthZInCertificate() throws Exception { - restartBookies(serverConf -> { - serverConf.setBookieAuthProviderFactoryClass(BookieAuthZFactory.class.getCanonicalName()); - serverConf.setAuthorizedRoles("testRole,testRole1"); - return serverConf; - }); - - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - - try { - testClient(clientConf, numBookies); - } catch (BKException.BKUnauthorizedAccessException bke) { - fail("Could not verify given role."); - } - } - - /** - * Verify that a bookie-side Auth plugin can access server certificates. - */ - @Test - public void testBookieAuthPluginDenyAccesstoClientWithoutTLSAuthentication() throws Exception { - restartBookies(c -> { - c.setTLSClientAuthentication(false); - c.setBookieAuthProviderFactoryClass( - AllowOnlyClientsWithX509Certificates.class.getName()); - return c; - }); - - secureBookieSideChannel = false; - secureBookieSideChannelPrincipals = null; - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - clientConf.setTLSClientAuthentication(false); - - try { - testClient(clientConf, numBookies); - fail("Shouldn't be able to connect"); - } catch (BKException.BKUnauthorizedAccessException authFailed) { - } catch (BKException.BKNotEnoughBookiesException notEnoughBookiesException) { - if (!useV2Protocol) { - fail("Unexpected exception occurred."); - } - } - - assertTrue(secureBookieSideChannel); - assertNotNull(secureBookieSideChannelPrincipals); - assertTrue(secureBookieSideChannelPrincipals.isEmpty()); - } - - /** - * Verify that a bookie-side Auth plugin can access server certificates over LocalTransport. - */ - @Test - public void testBookieAuthPluginDenyAccessToClientWithoutTLSAuthenticationLocal() throws Exception { - restartBookies(c -> { - c.setTLSClientAuthentication(false); - c.setBookieAuthProviderFactoryClass( - AllowOnlyClientsWithX509Certificates.class.getName()); - c.setDisableServerSocketBind(true); - c.setEnableLocalTransport(true); - return c; - }); - - secureBookieSideChannel = false; - secureBookieSideChannelPrincipals = null; - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - clientConf.setTLSClientAuthentication(false); - - try { - testClient(clientConf, numBookies); - fail("Shouldn't be able to connect"); - } catch (BKException.BKUnauthorizedAccessException authFailed) { - } catch (BKException.BKNotEnoughBookiesException notEnoughBookiesException) { - if (!useV2Protocol) { - fail("Unexpected exception occurred."); - } - } - - assertTrue(secureBookieSideChannel); - assertNotNull(secureBookieSideChannelPrincipals); - assertTrue(secureBookieSideChannelPrincipals.isEmpty()); - } - - /** - * Verify that a bookie-side Auth plugin can access server certificates. - */ - @Test - public void testBookieAuthPluginDenyAccessToClientWithoutTLS() throws Exception { - restartBookies(c -> { - c.setBookieAuthProviderFactoryClass( - AllowOnlyClientsWithX509Certificates.class.getName()); - return c; - }); - - secureBookieSideChannel = false; - secureBookieSideChannelPrincipals = null; - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - clientConf.setTLSProviderFactoryClass(null); - - try { - testClient(clientConf, numBookies); - fail("Shouldn't be able to connect"); - } catch (BKException.BKUnauthorizedAccessException authFailed) { - } - - assertFalse(secureBookieSideChannel); - assertNull(secureBookieSideChannelPrincipals); - } - - private static class AllowOnlyBookiesWithX509Certificates implements ClientAuthProvider.Factory { - - @Override - public String getPluginName() { - return "tls"; - } - - @Override - public void init(ClientConfiguration conf) { - } - - @Override - public ClientAuthProvider newProvider(ClientConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new ClientAuthProvider() { - - AuthCallbacks.GenericCallback completeCallback; - - @Override - public void init(AuthCallbacks.GenericCallback cb) { - this.completeCallback = cb; - } - - @Override - public void onProtocolUpgrade() { - secureClientSideChannel = addr.isSecure(); - secureClientSideChannelPrincipals = addr.getProtocolPrincipals(); - Collection certificates = addr.getProtocolPrincipals(); - if (addr.isSecure() && !certificates.isEmpty()) { - assertTrue(certificates.iterator().next() instanceof X509Certificate); - completeCallback.operationComplete(BKException.Code.OK, AuthToken.NULL); - } else { - completeCallback.operationComplete(BKException.Code.UnauthorizedAccessException, - AuthToken.NULL); - } - } - - @Override - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - } - }; - } - } - - private static class AllowOnlyClientsWithX509Certificates implements BookieAuthProvider.Factory { - - @Override - public String getPluginName() { - return "tls"; - } - - @Override - public void init(ServerConfiguration conf) throws IOException { - } - - @Override - public BookieAuthProvider newProvider(BookieConnectionPeer addr, - final AuthCallbacks.GenericCallback completeCb) { - return new BookieAuthProvider() { - - AuthCallbacks.GenericCallback completeCallback = completeCb; - - @Override - public void onProtocolUpgrade() { - secureBookieSideChannel = addr.isSecure(); - secureBookieSideChannelPrincipals = addr.getProtocolPrincipals(); - Collection certificates = addr.getProtocolPrincipals(); - if (addr.isSecure() && !certificates.isEmpty()) { - assertTrue(certificates.iterator().next() instanceof X509Certificate); - completeCallback.operationComplete(BKException.Code.OK, null); - } else { - completeCallback.operationComplete(BKException.Code.UnauthorizedAccessException, null); - } - } - - @Override - public void process(AuthToken m, AuthCallbacks.GenericCallback cb) { - } - }; - } - } - - /** - * Verify that a client will fail to connect to a server if it has asked for TLS, but it is not available. Verify - * that if there are enough TLS servers to fill the ensemble, it will eventually use those rather than the non-TLS - */ - @Test - public void testMixedCluster() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - int origNumBookies = numBookies; - - ServerConfiguration bookieConf = newServerConfiguration(); - bookieConf.setTLSProviderFactoryClass(TLSContextFactory.class.getName()); - startAndAddBookie(bookieConf); - testClient(clientConf, origNumBookies + 1); - } - - /** - * Verify that if the server hangs while an TLS client is trying to connect, the client can continue. - */ - @Test - public void testHungServer() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - CountDownLatch latch = new CountDownLatch(1); - sleepBookie(getBookie(0), latch); - try { - testClient(clientConf, numBookies); - fail("Shouldn't be able to connect"); - } catch (BKException.BKNotEnoughBookiesException nnbe) { - // correct response - } - LOG.info("latch countdown"); - latch.countDown(); - } - - /** - * Verify TLS and non-TLS channel counters. - */ - @Test - public void testTLSChannelCounters() throws Exception { - ClientConfiguration tlsClientconf = new ClientConfiguration(baseClientConf) - .setNumChannelsPerBookie(1); - ClientConfiguration nonTlsClientconf = new ClientConfiguration(baseClientConf) - .setNumChannelsPerBookie(1) - .setTLSProviderFactoryClass(null); - - TestStatsProvider tlsStatsProvider = new TestStatsProvider(); - TestStatsProvider nonTlsStatsProvider = new TestStatsProvider(); - BookKeeperTestClient tlsClient = new BookKeeperTestClient(tlsClientconf, tlsStatsProvider); - BookKeeperTestClient nonTlsClient = new BookKeeperTestClient(nonTlsClientconf, nonTlsStatsProvider); - - // IO load from clients - testClient(tlsClient, numBookies); - testClient(nonTlsClient, numBookies); - - // verify stats - for (int i = 0; i < numBookies; i++) { - BookieServer bookie = serverByIndex(i); - StringBuilder nameBuilder = new StringBuilder(BookKeeperClientStats.CHANNEL_SCOPE) - .append(".") - .append("bookie_") - .append(TestUtils.buildStatsCounterPathFromBookieID(bookie.getBookieId())) - .append("."); - // check stats on TLS enabled client - TestStatsProvider.TestCounter cntr = tlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.ACTIVE_TLS_CHANNEL_COUNTER); - - assertEquals("Mismatch TLS channel count", 1, - tlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.ACTIVE_TLS_CHANNEL_COUNTER).get().longValue()); - assertEquals("TLS handshake failure unexpected", 0, - tlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.FAILED_TLS_HANDSHAKE_COUNTER).get().longValue()); - assertEquals("Mismatch non-TLS channel count", 0, - tlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.ACTIVE_NON_TLS_CHANNEL_COUNTER).get().longValue()); - assertEquals("Connection failures unexpected", 0, - tlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.FAILED_CONNECTION_COUNTER).get().longValue()); - - // check stats on non-TLS enabled client - assertEquals("Mismatch TLS channel count", 0, - nonTlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.ACTIVE_TLS_CHANNEL_COUNTER).get().longValue()); - assertEquals("TLS handshake failure unexpected", 0, - nonTlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.FAILED_TLS_HANDSHAKE_COUNTER).get().longValue()); - assertEquals("Mismatch non-TLS channel count", 1, - nonTlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.ACTIVE_NON_TLS_CHANNEL_COUNTER).get().longValue()); - assertEquals("Connection failures unexpected", 0, - nonTlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.FAILED_CONNECTION_COUNTER).get().longValue()); - - bookie.shutdown(); - assertEquals("Mismatch TLS channel count", 0, - tlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.ACTIVE_TLS_CHANNEL_COUNTER).get().longValue()); - assertEquals("Mismatch non-TLS channel count", 0, - nonTlsClient.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.ACTIVE_NON_TLS_CHANNEL_COUNTER).get().longValue()); - - } - } - - /** - * Verify handshake failure due to missing entry in trust store. - */ - @Test - public void testHandshakeFailure() throws Exception { - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf) - .setNumChannelsPerBookie(1); - - // restart a bookie with wrong trust store - int restartBookieIdx = 0; - ServerConfiguration badBookieConf = confByIndex(restartBookieIdx); - - switch (serverTrustStoreFormat) { - case PEM: - badBookieConf.setTLSTrustStore(getResourcePath("server-cert.pem")); - break; - case JKS: - badBookieConf.setTLSTrustStore(getResourcePath("server-key.jks")) - .setTLSTrustStorePasswordPath(getResourcePath("keyStoreServerPassword.txt")); - break; - case PKCS12: - badBookieConf.setTLSTrustStore(getResourcePath("server-key.p12")) - .setTLSTrustStorePasswordPath(getResourcePath("keyStoreServerPassword.txt")); - break; - default: - throw new Exception("Unrecognized trust store format: " + serverTrustStoreFormat); - } - - - killBookie(restartBookieIdx); - LOG.info("Sleeping for 1s before restarting bookie with bad cert"); - Thread.sleep(1000); - BookieServer bookie = startAndAddBookie(badBookieConf).getServer(); - // Create ledger and write entries - TestStatsProvider testStatsProvider = new TestStatsProvider(); - BookKeeperTestClient client = new BookKeeperTestClient(clientConf, testStatsProvider); - byte[] passwd = "testPassword".getBytes(); - int numEntries = 2; - byte[] testEntry = "testEntry".getBytes(); - - // should fail to write entries whey WQ == AQ == 3 - try (LedgerHandle lh = client.createLedger(numBookies, numBookies, numBookies, DigestType.CRC32, passwd)) { - for (int i = 0; i <= numEntries; i++) { - lh.addEntry(testEntry); - } - fail("Should have failed with not enough bookies to write"); - } catch (BKException.BKNotEnoughBookiesException bke) { - // expected - } - - // check failed handshake counter - StringBuilder nameBuilder = new StringBuilder(BookKeeperClientStats.CHANNEL_SCOPE) - .append(".") - .append("bookie_") - .append(TestUtils.buildStatsCounterPathFromBookieID(bookie.getBookieId())) - .append("."); - assertEquals("TLS handshake failure expected", 1, - client.getTestStatsProvider().getCounter(nameBuilder - + BookKeeperClientStats.FAILED_TLS_HANDSHAKE_COUNTER).get().longValue()); - } - - /** - * Verify that a client fails to connect to bookie if hostname verification - * fails. - */ - @Test - public void testClientAuthPluginWithHostnameVerificationEnabled() throws Exception { - secureClientSideChannel = false; - secureClientSideChannelPrincipals = null; - ClientConfiguration clientConf = new ClientConfiguration(baseClientConf); - - clientConf.setClientAuthProviderFactoryClass(AllowOnlyBookiesWithX509Certificates.class.getName()); - clientConf.setHostnameVerificationEnabled(true); - try { - testClient(clientConf, numBookies); - fail("should have failed with unauthorized exception"); - } catch (BKException.BKNotEnoughBookiesException e) { - // Ok. - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedgerTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedgerTest.java deleted file mode 100644 index 66d1d943af1..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedgerTest.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.HashSet; -import java.util.List; -import java.util.PrimitiveIterator; -import java.util.Set; -import org.junit.Test; - -/** - * Testsuite for AvailabilityOfEntriesOfLedger. - */ -public class AvailabilityOfEntriesOfLedgerTest { - @Test - public void testWithItrConstructor() { - long[][] arrays = { - { 0, 1, 2 }, - { 1, 2}, - { 1, 2, 3, 5, 6, 7, 8 }, - { 0, 1, 5 }, - { 3 }, - { 1, 2, 4, 5, 7, 8 }, - {}, - {0}, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 1001, 10000, 20000, 20001 } - }; - for (int i = 0; i < arrays.length; i++) { - long[] tempArray = arrays[i]; - PrimitiveIterator.OfLong primitiveIterator = Arrays.stream(tempArray).iterator(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = new AvailabilityOfEntriesOfLedger( - primitiveIterator); - assertEquals("Expected total number of entries", tempArray.length, - availabilityOfEntriesOfLedger.getTotalNumOfAvailableEntries()); - for (int j = 0; j < tempArray.length; j++) { - assertTrue(tempArray[j] + " is supposed to be available", - availabilityOfEntriesOfLedger.isEntryAvailable(tempArray[j])); - } - } - } - - @Test - public void testWithItrConstructorWithDuplicates() { - long[][] arrays = { - { 1, 2, 2, 3 }, - { 1, 2, 3, 5, 5, 6, 7, 8, 8 }, - { 1, 1, 5, 5 }, - { 3, 3 }, - { 1, 1, 2, 4, 5, 8, 9, 9, 9, 9, 9 }, - {}, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 17, 100, 1000, 1000, 1001, 10000, 10000, 20000, 20001 } - }; - for (int i = 0; i < arrays.length; i++) { - long[] tempArray = arrays[i]; - Set tempSet = new HashSet(); - for (int k = 0; k < tempArray.length; k++) { - tempSet.add(tempArray[k]); - } - PrimitiveIterator.OfLong primitiveIterator = Arrays.stream(tempArray).iterator(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = new AvailabilityOfEntriesOfLedger( - primitiveIterator); - assertEquals("Expected total number of entries", tempSet.size(), - availabilityOfEntriesOfLedger.getTotalNumOfAvailableEntries()); - for (int j = 0; j < tempArray.length; j++) { - assertTrue(tempArray[j] + " is supposed to be available", - availabilityOfEntriesOfLedger.isEntryAvailable(tempArray[j])); - } - } - } - - @Test - public void testSerializeDeserialize() { - long[][] arrays = { - { 0, 1, 2 }, - { 1, 2 }, - { 1, 2, 3, 5, 6, 7, 8 }, - { 0, 1, 5 }, - { 3 }, - { 1, 2, 4, 5, 7, 8 }, - { }, - { 0 }, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 1001, 10000, 20000, 20001 } - }; - for (int i = 0; i < arrays.length; i++) { - long[] tempArray = arrays[i]; - PrimitiveIterator.OfLong primitiveIterator = Arrays.stream(tempArray).iterator(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = new AvailabilityOfEntriesOfLedger( - primitiveIterator); - byte[] serializedState = availabilityOfEntriesOfLedger.serializeStateOfEntriesOfLedger(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedgerUsingSer = new AvailabilityOfEntriesOfLedger( - serializedState); - assertEquals("Expected total number of entries", tempArray.length, - availabilityOfEntriesOfLedgerUsingSer.getTotalNumOfAvailableEntries()); - for (int j = 0; j < tempArray.length; j++) { - assertTrue(tempArray[j] + " is supposed to be available", - availabilityOfEntriesOfLedgerUsingSer.isEntryAvailable(tempArray[j])); - } - } - } - - @Test - public void testSerializeDeserializeWithItrConstructorWithDuplicates() { - long[][] arrays = { - { 1, 2, 2, 3 }, - { 1, 2, 3, 5, 5, 6, 7, 8, 8 }, - { 1, 1, 5, 5 }, - { 3, 3 }, - { 1, 1, 2, 4, 5, 8, 9, 9, 9, 9, 9 }, - {}, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 17, 100, 1000, 1000, 1001, 10000, 10000, 20000, 20001 } - }; - for (int i = 0; i < arrays.length; i++) { - long[] tempArray = arrays[i]; - Set tempSet = new HashSet(); - for (int k = 0; k < tempArray.length; k++) { - tempSet.add(tempArray[k]); - } - PrimitiveIterator.OfLong primitiveIterator = Arrays.stream(tempArray).iterator(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = new AvailabilityOfEntriesOfLedger( - primitiveIterator); - byte[] serializedState = availabilityOfEntriesOfLedger.serializeStateOfEntriesOfLedger(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedgerUsingSer = new AvailabilityOfEntriesOfLedger( - serializedState); - assertEquals("Expected total number of entries", tempSet.size(), - availabilityOfEntriesOfLedgerUsingSer.getTotalNumOfAvailableEntries()); - for (int j = 0; j < tempArray.length; j++) { - assertTrue(tempArray[j] + " is supposed to be available", - availabilityOfEntriesOfLedgerUsingSer.isEntryAvailable(tempArray[j])); - } - } - } - - @Test - public void testNonExistingEntries() { - long[][] arrays = { - { 0, 1, 2 }, - { 1, 2, 3, 5, 6, 7, 8 }, - { 1, 5 }, - { 3 }, - { 1, 2, 4, 5, 7, 8 }, - {}, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 1001, 10000, 20000, 20001 } - }; - /** - * corresponding non-existing entries for 'arrays' - */ - long[][] nonExistingEntries = { - { 3 }, - { 0, 4, 9, 100, 101 }, - { 0, 2, 3, 6, 9 }, - { 0, 1, 2, 4, 5, 6 }, - { 0, 3, 9, 10, 11, 100, 1000 }, - { 0, 1, 2, 3, 4, 5 }, - { 4, 18, 1002, 19999, 20003 } - }; - for (int i = 0; i < arrays.length; i++) { - long[] tempArray = arrays[i]; - long[] nonExistingElementsTempArray = nonExistingEntries[i]; - PrimitiveIterator.OfLong primitiveIterator = Arrays.stream(tempArray).iterator(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = new AvailabilityOfEntriesOfLedger( - primitiveIterator); - - for (int j = 0; j < nonExistingElementsTempArray.length; j++) { - assertFalse(nonExistingElementsTempArray[j] + " is not supposed to be available", - availabilityOfEntriesOfLedger.isEntryAvailable(nonExistingElementsTempArray[j])); - } - } - } - - @Test - public void testGetUnavailableEntries() { - /* - * AvailabilityOfEntriesOfLedger is going to be created with this - * entries. It is equivalent to considering that Bookie has these - * entries. - */ - long[][] availableEntries = { - { 1, 2}, - { 0, 1, 2 }, - { 1, 2, 3, 5, 6, 7, 8 }, - { 1, 5 }, - { 3 }, - { 1, 2, 4, 5, 7, 8 }, - {}, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 1001, 10000, 20000, 20001 } - }; - - /* - * getUnavailableEntries method is going to be called with these entries - * as expected to contain. - */ - long[][] expectedToContainEntries = { - { 1, 2}, - { 0, 1, 2, 3, 5 }, - { 1, 2, 5, 7, 8 }, - { 2, 7 }, - { 3 }, - { 1, 5, 7, 8, 9, 10 }, - { 0, 1, 2, 3, 4, 5 }, - { 4, 18, 1002, 19999, 20003 } - }; - - /* - * Considering what AvailabilityOfEntriesOfLedger contains - * (availableEntries), what it is expected to contain - * (expectedToContainEntries), following are the entries which are - * supposed to be reported as unavailable (unavailableEntries). - */ - long[][] unavailableEntries = { - { }, - { 3, 5 }, - { }, - { 2, 7 }, - { }, - { 9, 10 }, - { 0, 1, 2, 3, 4, 5 }, - { 4, 18, 1002, 19999, 20003 } - }; - - for (int i = 0; i < availableEntries.length; i++) { - long[] availableEntriesTempArray = availableEntries[i]; - long[] expectedToContainEntriesTempArray = expectedToContainEntries[i]; - long[] unavailableEntriesTempArray = unavailableEntries[i]; - List unavailableEntriesTempList = new ArrayList(); - for (int j = 0; j < unavailableEntriesTempArray.length; j++) { - unavailableEntriesTempList.add(unavailableEntriesTempArray[j]); - } - - PrimitiveIterator.OfLong primitiveIterator = Arrays.stream(availableEntriesTempArray).iterator(); - AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = new AvailabilityOfEntriesOfLedger( - primitiveIterator); - - long startEntryId; - long lastEntryId; - if (expectedToContainEntriesTempArray[0] == 0) { - startEntryId = expectedToContainEntriesTempArray[0]; - lastEntryId = expectedToContainEntriesTempArray[expectedToContainEntriesTempArray.length - 1]; - } else { - startEntryId = expectedToContainEntriesTempArray[0] - 1; - lastEntryId = expectedToContainEntriesTempArray[expectedToContainEntriesTempArray.length - 1] + 1; - } - BitSet expectedToContainEntriesBitSet = new BitSet((int) (lastEntryId - startEntryId + 1)); - for (int ind = 0; ind < expectedToContainEntriesTempArray.length; ind++) { - int entryId = (int) expectedToContainEntriesTempArray[ind]; - expectedToContainEntriesBitSet.set(entryId - (int) startEntryId); - } - - List actualUnavailableEntries = availabilityOfEntriesOfLedger.getUnavailableEntries(startEntryId, - lastEntryId, expectedToContainEntriesBitSet); - assertEquals("Unavailable Entries", unavailableEntriesTempList, actualUnavailableEntries); - } - } - - @Test - public void testEmptyAvailabilityOfEntriesOfLedger() { - AvailabilityOfEntriesOfLedger emptyOne = AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER; - assertEquals("expected totalNumOfAvailableEntries", 0, emptyOne.getTotalNumOfAvailableEntries()); - assertFalse("empty one is not supposed to contain any entry", emptyOne.isEntryAvailable(100L)); - long startEntryId = 100; - long lastEntryId = 105; - BitSet bitSetOfAvailability = new BitSet((int) (lastEntryId - startEntryId + 1)); - for (int i = 0; i < bitSetOfAvailability.length(); i++) { - if ((i % 2) == 0) { - bitSetOfAvailability.set(i); - } - } - List unavailableEntries = emptyOne.getUnavailableEntries(startEntryId, lastEntryId, bitSetOfAvailability); - assertEquals("Num of unavailable entries", bitSetOfAvailability.cardinality(), unavailableEntries.size()); - for (int i = 0; i < bitSetOfAvailability.length(); i++) { - long entryId = startEntryId + i; - if (bitSetOfAvailability.get(i)) { - assertTrue("Unavailable entry", unavailableEntries.contains(entryId)); - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/ByteBufListTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/ByteBufListTest.java deleted file mode 100644 index 88de17d0a9d..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/ByteBufListTest.java +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.util; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelProgressivePromise; -import io.netty.channel.ChannelPromise; -import io.netty.util.Attribute; -import io.netty.util.AttributeKey; -import io.netty.util.ReferenceCountUtil; -import io.netty.util.concurrent.EventExecutor; -import java.net.SocketAddress; -import org.junit.Test; - -/** - * Unit tests for {@link ByteBufList}. - */ -public class ByteBufListTest { - @Test - public void testSingle() throws Exception { - ByteBuf b1 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b1.writerIndex(b1.capacity()); - ByteBufList buf = ByteBufList.get(b1); - - assertEquals(1, buf.size()); - assertEquals(128, buf.readableBytes()); - assertEquals(b1, buf.getBuffer(0)); - - assertEquals(buf.refCnt(), 1); - assertEquals(b1.refCnt(), 1); - - buf.release(); - - assertEquals(buf.refCnt(), 0); - assertEquals(b1.refCnt(), 0); - } - - @Test - public void testDouble() throws Exception { - ByteBuf b1 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b1.writerIndex(b1.capacity()); - ByteBuf b2 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b2.writerIndex(b2.capacity()); - ByteBufList buf = ByteBufList.get(b1, b2); - - assertEquals(2, buf.size()); - assertEquals(256, buf.readableBytes()); - assertEquals(b1, buf.getBuffer(0)); - assertEquals(b2, buf.getBuffer(1)); - - assertEquals(buf.refCnt(), 1); - assertEquals(b1.refCnt(), 1); - assertEquals(b2.refCnt(), 1); - - buf.release(); - - assertEquals(buf.refCnt(), 0); - assertEquals(b1.refCnt(), 0); - assertEquals(b2.refCnt(), 0); - } - - @Test - public void testClone() throws Exception { - ByteBuf b1 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b1.writerIndex(b1.capacity()); - ByteBuf b2 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b2.writerIndex(b2.capacity()); - ByteBufList buf = ByteBufList.get(b1, b2); - - ByteBufList clone = ByteBufList.clone(buf); - - assertEquals(2, buf.size()); - assertEquals(256, buf.readableBytes()); - assertEquals(b1, buf.getBuffer(0)); - assertEquals(b2, buf.getBuffer(1)); - - assertEquals(2, clone.size()); - assertEquals(256, clone.readableBytes()); - assertEquals(b1, clone.getBuffer(0)); - assertEquals(b2, clone.getBuffer(1)); - - assertEquals(buf.refCnt(), 1); - assertEquals(clone.refCnt(), 1); - assertEquals(b1.refCnt(), 2); - assertEquals(b2.refCnt(), 2); - - buf.release(); - - assertEquals(buf.refCnt(), 0); - assertEquals(clone.refCnt(), 1); - assertEquals(b1.refCnt(), 1); - assertEquals(b2.refCnt(), 1); - - clone.release(); - - assertEquals(buf.refCnt(), 0); - assertEquals(clone.refCnt(), 0); - assertEquals(b1.refCnt(), 0); - assertEquals(b2.refCnt(), 0); - } - - @Test - public void testGetBytes() throws Exception { - ByteBufList buf = ByteBufList.get(Unpooled.wrappedBuffer("hello".getBytes()), - Unpooled.wrappedBuffer("world".getBytes())); - - assertArrayEquals("helloworld".getBytes(), buf.toArray()); - - buf.prepend(Unpooled.wrappedBuffer("prefix-".getBytes())); - assertArrayEquals("prefix-helloworld".getBytes(), buf.toArray()); - - // Bigger buffer - byte[] buf100 = new byte[100]; - int res = buf.getBytes(buf100); - - assertEquals("prefix-helloworld".length(), res); - - // Smaller buffer - byte[] buf4 = new byte[4]; - res = buf.getBytes(buf4); - - assertEquals(4, res); - assertEquals("pref", new String(buf4)); - } - - @Test - public void testCoalesce() throws Exception { - ByteBufList buf = ByteBufList.get(Unpooled.wrappedBuffer("hello".getBytes()), - Unpooled.wrappedBuffer("world".getBytes())); - - assertEquals(Unpooled.wrappedBuffer("helloworld".getBytes()), ByteBufList.coalesce(buf)); - } - - @Test - public void testRetain() throws Exception { - ByteBuf b1 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b1.writerIndex(b1.capacity()); - ByteBufList buf = ByteBufList.get(b1); - - assertEquals(1, buf.size()); - assertEquals(128, buf.readableBytes()); - assertEquals(b1, buf.getBuffer(0)); - - assertEquals(buf.refCnt(), 1); - assertEquals(b1.refCnt(), 1); - - buf.retain(); - - assertEquals(buf.refCnt(), 2); - assertEquals(b1.refCnt(), 1); - - buf.release(); - - assertEquals(buf.refCnt(), 1); - assertEquals(b1.refCnt(), 1); - - buf.release(); - - assertEquals(buf.refCnt(), 0); - assertEquals(b1.refCnt(), 0); - } - - @Test - public void testEncoder() throws Exception { - ByteBuf b1 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b1.writerIndex(b1.capacity()); - ByteBuf b2 = PooledByteBufAllocator.DEFAULT.heapBuffer(128, 128); - b2.writerIndex(b2.capacity()); - ByteBufList buf = ByteBufList.get(b1, b2); - - ChannelHandlerContext ctx = new MockChannelHandlerContext(); - - ByteBufList.ENCODER.write(ctx, buf, null); - - assertEquals(buf.refCnt(), 0); - assertEquals(b1.refCnt(), 0); - assertEquals(b2.refCnt(), 0); - } - - class MockChannelHandlerContext implements ChannelHandlerContext { - @Override - public ChannelFuture bind(SocketAddress localAddress) { - return null; - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress) { - return null; - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { - return null; - } - - @Override - public ChannelFuture disconnect() { - return null; - } - - @Override - public ChannelFuture close() { - return null; - } - - @Override - public ChannelFuture deregister() { - return null; - } - - @Override - public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { - return null; - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { - return null; - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - return null; - } - - @Override - public ChannelFuture disconnect(ChannelPromise promise) { - return null; - } - - @Override - public ChannelFuture close(ChannelPromise promise) { - return null; - } - - @Override - public ChannelFuture deregister(ChannelPromise promise) { - return null; - } - - @Override - public ChannelFuture write(Object msg) { - ReferenceCountUtil.release(msg); - return null; - } - - @Override - public ChannelFuture write(Object msg, ChannelPromise promise) { - ReferenceCountUtil.release(msg); - return null; - } - - @Override - public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { - ReferenceCountUtil.release(msg); - return null; - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - ReferenceCountUtil.release(msg); - return null; - } - - @Override - public ChannelPromise newPromise() { - return null; - } - - @Override - public ChannelProgressivePromise newProgressivePromise() { - return null; - } - - @Override - public ChannelFuture newSucceededFuture() { - return null; - } - - @Override - public ChannelFuture newFailedFuture(Throwable cause) { - return null; - } - - @Override - public ChannelPromise voidPromise() { - return null; - } - - @Override - public Channel channel() { - return null; - } - - @Override - public EventExecutor executor() { - return null; - } - - @Override - public String name() { - return null; - } - - @Override - public ChannelHandler handler() { - return null; - } - - @Override - public boolean isRemoved() { - return false; - } - - @Override - public ChannelHandlerContext fireChannelRegistered() { - return null; - } - - @Override - public ChannelHandlerContext fireChannelUnregistered() { - return null; - } - - @Override - public ChannelHandlerContext fireChannelActive() { - return null; - } - - @Override - public ChannelHandlerContext fireChannelInactive() { - return null; - } - - @Override - public ChannelHandlerContext fireExceptionCaught(Throwable cause) { - return null; - } - - @Override - public ChannelHandlerContext fireUserEventTriggered(Object evt) { - return null; - } - - @Override - public ChannelHandlerContext fireChannelRead(Object msg) { - return null; - } - - @Override - public ChannelHandlerContext fireChannelReadComplete() { - return null; - } - - @Override - public ChannelHandlerContext fireChannelWritabilityChanged() { - return null; - } - - @Override - public ChannelHandlerContext read() { - return null; - } - - @Override - public ChannelHandlerContext flush() { - return null; - } - - @Override - public ChannelPipeline pipeline() { - return null; - } - - @Override - public ByteBufAllocator alloc() { - return null; - } - - @Override - @Deprecated - public Attribute attr(AttributeKey key) { - return null; - } - - @Override - @Deprecated - public boolean hasAttr(AttributeKey key) { - return false; - } - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/IteratorUtilityTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/IteratorUtilityTest.java deleted file mode 100644 index 8fb41cce4d7..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/IteratorUtilityTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright The Apache Software Foundation - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.PrimitiveIterator; -import java.util.function.Consumer; -import java.util.stream.IntStream; -import org.junit.Assert; -import org.junit.Test; - -/** - * Testsuite for IteratorUtility methods. - */ -public class IteratorUtilityTest { - - @Test - public void testWithPrimitiveItrMerge() { - long[][] arrays = { - { 0, 1, 2 }, - { 0, 1 }, - { 1, 2 }, - { 1, 2, 3, 5, 6, 7, 8 }, - { 1, 2, 3, 5, 6, 7, 8 }, - { 0, 1, 5 }, - { 3 }, - { 1, 2, 4, 5, 7, 8 }, - {}, - {}, - { 0 }, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 1001, 10000, 20000, 20001 }, - { 201, 202, 203, 205, 206, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 20100, 201000, - 201001, 2010000, 2020000, 2020001 } - }; - for (int i = 0; i < arrays.length; i++) { - for (int j = i + 1; j < arrays.length; j++) { - long[] tempArray1 = arrays[i]; - long[] tempArray2 = arrays[j]; - HashSet unionSet = new HashSet(); - for (int k = 0; k < tempArray1.length; k++) { - unionSet.add(tempArray1[k]); - } - for (int k = 0; k < tempArray2.length; k++) { - unionSet.add(tempArray2[k]); - } - - PrimitiveIterator.OfLong primitiveIterator1 = Arrays.stream(tempArray1).iterator(); - PrimitiveIterator.OfLong primitiveIterator2 = Arrays.stream(tempArray2).iterator(); - - PrimitiveIterator.OfLong mergedItr = IteratorUtility.mergePrimitiveLongIterator(primitiveIterator1, - primitiveIterator2); - ArrayList mergedArrayList = new ArrayList(); - Consumer addMethod = mergedArrayList::add; - mergedItr.forEachRemaining(addMethod); - int mergedListSize = mergedArrayList.size(); - Assert.assertEquals("Size of the mergedArrayList", unionSet.size(), mergedArrayList.size()); - Assert.assertTrue("mergedArrayList should contain all elements in unionSet", - mergedArrayList.containsAll(unionSet)); - Assert.assertTrue("Merged Iterator should be sorted", IntStream.range(0, mergedListSize - 1) - .allMatch(k -> mergedArrayList.get(k) <= mergedArrayList.get(k + 1))); - Assert.assertTrue("All elements of tempArray1 should be in mergedArrayList", - IntStream.range(0, tempArray1.length).allMatch(k -> mergedArrayList.contains(tempArray1[k]))); - Assert.assertTrue("All elements of tempArray2 should be in mergedArrayList", - IntStream.range(0, tempArray2.length).allMatch(k -> mergedArrayList.contains(tempArray2[k]))); - } - } - } - - @Test - public void testWithItrMerge() { - long[][] arrays = { - { 0, 1, 2 }, - { 0, 1 }, - { 1, 2 }, - { 1, 2, 3, 5, 6, 7, 8 }, - { 1, 2, 3, 5, 6, 7, 8 }, - { 0, 1, 5 }, - { 3 }, - { 1, 2, 4, 5, 7, 8 }, - {}, - {}, - { 0 }, - { 1, 2, 3, 5, 6, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 1001, 10000, 20000, 20001 }, - { 201, 202, 203, 205, 206, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 20100, 201000, - 201001, 2010000, 2020000, 2020001 } - }; - for (int i = 0; i < arrays.length; i++) { - for (int j = i + 1; j < arrays.length; j++) { - long[] tempArray1 = arrays[i]; - ArrayList tempArrayList1 = new ArrayList(); - IntStream.range(0, tempArray1.length).forEach((k) -> tempArrayList1.add(tempArray1[k])); - long[] tempArray2 = arrays[j]; - ArrayList tempArrayList2 = new ArrayList(); - IntStream.range(0, tempArray2.length).forEach((k) -> tempArrayList2.add(tempArray2[k])); - HashSet unionSet = new HashSet(); - unionSet.addAll(tempArrayList1); - unionSet.addAll(tempArrayList2); - - Iterator itr1 = tempArrayList1.iterator(); - Iterator itr2 = tempArrayList2.iterator(); - - Iterator mergedItr = IteratorUtility.mergeIteratorsForPrimitiveLongIterator(itr1, itr2, - Long::compare, (l) -> l); - ArrayList mergedArrayList = new ArrayList(); - Consumer addMethod = mergedArrayList::add; - mergedItr.forEachRemaining(addMethod); - int mergedListSize = mergedArrayList.size(); - Assert.assertEquals("Size of the mergedArrayList", unionSet.size(), mergedArrayList.size()); - Assert.assertTrue("mergedArrayList should contain all elements in unionSet", - mergedArrayList.containsAll(unionSet)); - Assert.assertTrue("Merged Iterator should be sorted", IntStream.range(0, mergedListSize - 1) - .allMatch(k -> mergedArrayList.get(k) <= mergedArrayList.get(k + 1))); - Assert.assertTrue("All elements of tempArray1 should be in mergedArrayList", - IntStream.range(0, tempArray1.length).allMatch(k -> mergedArrayList.contains(tempArray1[k]))); - Assert.assertTrue("All elements of tempArray2 should be in mergedArrayList", - IntStream.range(0, tempArray2.length).allMatch(k -> mergedArrayList.contains(tempArray2[k]))); - } - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/LoggerOutput.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/LoggerOutput.java deleted file mode 100644 index 610997cba91..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/LoggerOutput.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util; - -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.NullAppender; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; -import org.mockito.ArgumentCaptor; -import org.slf4j.Marker; -import org.slf4j.event.Level; -import org.slf4j.event.LoggingEvent; - -/** - * A utility class for testing logger output. - */ -public class LoggerOutput implements TestRule { - - private NullAppender logAppender; - private ArgumentCaptor logEventCaptor; - private final List>> logEventExpectations = new ArrayList<>(); - - public void expect(Consumer> expectation) { - if (logEventCaptor == null) { - logEventCaptor = ArgumentCaptor.forClass(LogEvent.class); - } - logEventExpectations.add(expectation); - } - - @Override - public Statement apply(final Statement base, Description description) { - return new Statement() { - - @Override - public void evaluate() throws Throwable { - LoggerContext lc = (LoggerContext) LogManager.getContext(false); - logAppender = spy(NullAppender.createAppender(UUID.randomUUID().toString())); - logAppender.start(); - lc.getConfiguration().addAppender(logAppender); - lc.getRootLogger().addAppender(lc.getConfiguration().getAppender(logAppender.getName())); - lc.updateLoggers(); - try { - base.evaluate(); - if (!logEventExpectations.isEmpty()) { - verify(logAppender, atLeastOnce()).append(logEventCaptor.capture()); - List logEvents = logEventCaptor.getAllValues().stream() - .map(LoggerOutput::toSlf4j) - .collect(Collectors.toList()); - for (Consumer> expectation : logEventExpectations) { - expectation.accept(logEvents); - } - } - } finally { - lc.getRootLogger().removeAppender(lc.getConfiguration().getAppender(logAppender.getName())); - lc.updateLoggers(); - logEventExpectations.clear(); - logEventCaptor = null; - } - } - }; - } - - private static LoggingEvent toSlf4j(LogEvent log4jEvent) { - return new LoggingEvent() { - @Override - public Level getLevel() { - switch (log4jEvent.getLevel().toString()) { - case "FATAL": - case "ERROR": return Level.ERROR; - case "WARN": return Level.WARN; - case "INFO": return Level.INFO; - case "DEBUG": return Level.DEBUG; - case "TRACE": - case "ALL": - case "OFF": - default: return Level.TRACE; - } - } - - @Override - public Marker getMarker() { - return null; - } - - @Override - public String getLoggerName() { - return log4jEvent.getLoggerName(); - } - - @Override - public String getMessage() { - return log4jEvent.getMessage().getFormattedMessage(); - } - - @Override - public String getThreadName() { - return log4jEvent.getThreadName(); - } - - @Override - public Object[] getArgumentArray() { - return new Object[0]; - } - - @Override - public long getTimeStamp() { - return log4jEvent.getTimeMillis(); - } - - @Override - public Throwable getThrowable() { - return null; - } - }; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/NettyChannelUtilTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/NettyChannelUtilTest.java deleted file mode 100644 index ea47d83ec75..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/NettyChannelUtilTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util; - -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelOutboundInvoker; -import io.netty.channel.ChannelPromise; -import io.netty.channel.VoidChannelPromise; -import java.nio.charset.StandardCharsets; -import org.junit.Test; - -public class NettyChannelUtilTest { - - @Test - public void testWriteAndFlushWithVoidPromise() { - final ChannelOutboundInvoker ctx = mock(ChannelOutboundInvoker.class); - final VoidChannelPromise voidChannelPromise = new VoidChannelPromise(mock(Channel.class), true); - when(ctx.voidPromise()).thenReturn(voidChannelPromise); - final byte[] data = "test".getBytes(StandardCharsets.UTF_8); - final ByteBuf byteBuf = Unpooled.wrappedBuffer(data, 0, data.length); - try { - NettyChannelUtil.writeAndFlushWithVoidPromise(ctx, byteBuf); - verify(ctx).writeAndFlush(same(byteBuf), same(voidChannelPromise)); - verify(ctx).voidPromise(); - } finally { - byteBuf.release(); - } - } - - @Test - public void testWriteAndFlushWithClosePromise() { - final ChannelOutboundInvoker ctx = mock(ChannelOutboundInvoker.class); - final ChannelPromise promise = mock(ChannelPromise.class); - - final byte[] data = "test".getBytes(StandardCharsets.UTF_8); - final ByteBuf byteBuf = Unpooled.wrappedBuffer(data, 0, data.length); - when(ctx.writeAndFlush(same(byteBuf))).thenReturn(promise); - try { - NettyChannelUtil.writeAndFlushWithClosePromise(ctx, byteBuf); - verify(ctx).writeAndFlush(same(byteBuf)); - verify(promise).addListener(same(ChannelFutureListener.CLOSE)); - } finally { - byteBuf.release(); - } - } - -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/StaticDNSResolver.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/StaticDNSResolver.java deleted file mode 100644 index 72e61212fbd..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/StaticDNSResolver.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import org.apache.bookkeeper.client.ITopologyAwareEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.RackChangeNotifier; -import org.apache.bookkeeper.net.AbstractDNSToSwitchMapping; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieNode; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.bookkeeper.net.NetworkTopology; -import org.apache.bookkeeper.net.NodeBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implements {@link DNSToSwitchMapping} via static mappings. Used in test cases to simulate racks. - */ -public class StaticDNSResolver extends AbstractDNSToSwitchMapping implements RackChangeNotifier { - - static final Logger LOG = LoggerFactory.getLogger(StaticDNSResolver.class); - - private static final ConcurrentMap name2Racks = new ConcurrentHashMap(); - - public static void addNodeToRack(String name, String rack) { - name2Racks.put(name, rack); - if (LOG.isDebugEnabled()) { - LOG.debug("Add node {} to rack {}.", name, rack); - } - } - - public static String getRack(String name) { - String rack = name2Racks.get(name); - if (null == rack) { - rack = NetworkTopology.DEFAULT_REGION_AND_RACK; - } - return rack; - } - - public static String getRegion(String name) { - String[] parts = getRack(name).split(NodeBase.PATH_SEPARATOR_STR); - if (parts.length <= 1) { - return NetworkTopology.DEFAULT_REGION; - } else { - return parts[1]; - } - } - - public static void reset() { - name2Racks.clear(); - } - - @Override - public List resolve(List names) { - if (getBookieAddressResolver() == null) { - // test that this istance has been properly initialized - throw new IllegalStateException("bookieAddressResolver was not set"); - } - List racks = new ArrayList(); - for (String n : names) { - String rack = name2Racks.get(n); - if (LOG.isDebugEnabled()) { - LOG.debug("Resolve name {} to rack {}.", n, rack); - } - racks.add(rack); - } - return racks; - } - - @Override - public void reloadCachedMappings() { - // nop - } - - private static ITopologyAwareEnsemblePlacementPolicy rackawarePolicy = null; - - @Override - public void registerRackChangeListener(ITopologyAwareEnsemblePlacementPolicy rackawareEnsemblePolicy) { - rackawarePolicy = rackawareEnsemblePolicy; - } - - public static void changeRack(List bookieAddressList, List rack) { - List bookieIds = new ArrayList<>(); - for (int i = 0; i < bookieAddressList.size(); i++) { - BookieSocketAddress bkAddress = bookieAddressList.get(i); - name2Racks.put(bkAddress.getHostName(), rack.get(i)); - bookieIds.add(bkAddress.toBookieId()); - } - rackawarePolicy.onBookieRackChange(bookieIds); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/SubTreeCacheTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/SubTreeCacheTest.java deleted file mode 100644 index aea9b962aae..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/SubTreeCacheTest.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.KeeperException.NoNodeException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Test the subtree cache. - */ -public class SubTreeCacheTest { - class TestTreeProvider implements SubTreeCache.TreeProvider { - class Node { - Watcher watcher = null; - public Map children = new HashMap<>(); - } - - final Node root = new Node(); - - Node getNode(String path) throws KeeperException { - String[] pathSegments = path.split("/"); - Node cur = root; - for (String segment : pathSegments) { - if (segment.length() == 0) { - continue; // ignore leading empty one for leading / - } - if (cur.children.containsKey(segment)) { - cur = cur.children.get(segment); - } else { - throw KeeperException.create(KeeperException.Code.NONODE); - } - } - return cur; - } - - @Override - public List getChildren( - String path, Watcher watcher) throws InterruptedException, KeeperException { - Node node = getNode(path); - - /* Enforce only one live watch per node */ - Assert.assertTrue(null == node.watcher); - - node.watcher = watcher; - return new ArrayList(node.children.keySet()); - } - - public void createNode(String path) throws KeeperException { - String[] segments = path.split("/"); - if (segments.length == 0) { - throw KeeperException.create(KeeperException.Code.NONODE); - } - String child = segments[segments.length - 1]; - String[] parentSegments = Arrays.copyOfRange(segments, 0, segments.length - 1); - Node parent = getNode(String.join("/", parentSegments)); - if (parent.children.containsKey(child)) { - throw KeeperException.create(KeeperException.Code.NODEEXISTS); - } else { - parent.children.put(child, new Node()); - if (null != parent.watcher) { - parent.watcher.process( - new WatchedEvent( - Watcher.Event.EventType.NodeCreated, - Watcher.Event.KeeperState.SyncConnected, - path)); - parent.watcher = null; - } - } - } - - public void removeNode(String path) throws KeeperException { - String[] segments = path.split("/"); - if (segments.length == 0) { - throw KeeperException.create(KeeperException.Code.NONODE); - } - String child = segments[segments.length - 1]; - String[] parentSegments = Arrays.copyOfRange(segments, 0, segments.length - 1); - String parentPath = String.join("/", parentSegments); - Node parent = getNode(parentPath); - if (!parent.children.containsKey(child)) { - throw KeeperException.create(KeeperException.Code.NONODE); - } else { - Node cNode = parent.children.get(child); - if (!cNode.children.isEmpty()) { - throw KeeperException.create(KeeperException.Code.NOTEMPTY); - } else { - if (null != cNode.watcher) { - cNode.watcher.process( - new WatchedEvent( - Watcher.Event.EventType.NodeChildrenChanged, - Watcher.Event.KeeperState.SyncConnected, - path)); - cNode.watcher = null; - } - if (null != parent.watcher) { - parent.watcher.process( - new WatchedEvent( - Watcher.Event.EventType.NodeDeleted, - Watcher.Event.KeeperState.SyncConnected, - parentPath)); - parent.watcher = null; - } - parent.children.remove(child); - } - } - } - } - - TestTreeProvider tree = new TestTreeProvider(); - SubTreeCache cache = new SubTreeCache(tree); - - class TestWatch implements Watcher { - boolean fired = false; - - @Override - public void process(WatchedEvent event) { - fired = true; - } - - public boolean getFired() { - return fired; - } - } - - TestWatch setWatch() { - TestWatch watch = new TestWatch(); - cache.registerWatcher(watch); - return watch; - } - - void assertFired(TestWatch watch) { - Assert.assertTrue(watch.getFired()); - } - - void assertNotFired(TestWatch watch) { - Assert.assertFalse(watch.getFired()); - } - - class TestWatchGuard extends TestWatch implements AutoCloseable { - SubTreeCache.WatchGuard guard; - - void setGuard(SubTreeCache.WatchGuard guard) { - this.guard = guard; - } - - @Override - public void close() throws Exception { - guard.close(); - } - } - - TestWatchGuard setWatchWithGuard() { - TestWatchGuard watch = new TestWatchGuard(); - watch.setGuard(cache.registerWatcherWithGuard(watch)); - return watch; - } - - void readAssertChildren(String path, String[] children) throws KeeperException, InterruptedException { - SortedSet shouldBe = new TreeSet(Arrays.asList(children)); - List returned = cache.getChildren(path); - SortedSet is = new TreeSet(returned); - returned.clear(); // trip up implementations which return an internal reference - Assert.assertEquals(shouldBe, is); - } - - @Before - public void setUp() throws Exception { - String[] preCreate = - {"/a" - , "/a/a" - , "/a/a/a" - , "/a/a/b" - , "/a/b" - , "/a/c" - , "/b" - , "/b/a" - }; - for (String path : preCreate) { - tree.createNode(path); - } - } - - @Test - public void testNoUpdate() throws Exception { - TestWatch watch = setWatch(); - readAssertChildren("/a/a", new String[]{"a", "b"}); - assertNotFired(watch); - } - - @Test - public void testSingleCreate() throws Exception { - TestWatch watch = setWatch(); - readAssertChildren("/a/a", new String[]{"a", "b"}); - tree.createNode("/a/a/c"); - assertFired(watch); - } - - @Test - public void testSingleRemoval() throws Exception { - TestWatch watch = setWatch(); - readAssertChildren("/a/a", new String[]{"a", "b"}); - tree.removeNode("/a/a/b"); - assertFired(watch); - } - - @Test - public void testCancelation() throws Exception { - TestWatch watch = setWatch(); - readAssertChildren("/a/a", new String[]{"a", "b"}); - cache.cancelWatcher(watch); - tree.createNode("/a/a/c"); - assertNotFired(watch); - } - - @Test - public void testGuardCancelation() throws Exception { - TestWatch watch; - try (TestWatchGuard guard = setWatchWithGuard()) { - readAssertChildren("/a/a", new String[]{"a", "b"}); - watch = guard; - } - tree.createNode("/a/a/c"); - assertNotFired(watch); - } - - @Test - public void testGuardCancelationExceptional() throws Exception { - TestWatch watch = null; - try (TestWatchGuard guard = setWatchWithGuard()) { - watch = guard; - readAssertChildren("/z/a", new String[]{}); - } catch (Exception e) { - } - tree.createNode("/a/a/c"); - assertNotFired(watch); - } - - @Test - public void testDuplicateWatch() throws Exception { - try (TestWatchGuard watch = setWatchWithGuard()) { - readAssertChildren("/a/a", new String[]{"a", "b"}); - } - try (TestWatchGuard watch = setWatchWithGuard()) { - readAssertChildren("/a/a", new String[]{"a", "b"}); - assertNotFired(watch); - tree.createNode("/a/a/e"); - assertFired(watch); - } - } - - @Test(expected = NoNodeException.class) - public void testNoNode() throws Exception { - try (TestWatchGuard watch = setWatchWithGuard()) { - readAssertChildren("/z/a", new String[]{}); - } - } - - @Test - public void testRemoveEmptyNode() throws Exception { - try (TestWatchGuard watch = setWatchWithGuard()) { - readAssertChildren("/a/a/a", new String[]{}); - tree.removeNode("/a/a/a"); - assertFired(watch); - } - } - - @Test - public void doubleWatch() throws Exception { - try (TestWatchGuard watch1 = setWatchWithGuard()) { - readAssertChildren("/a/a", new String[]{"a", "b"}); - try (TestWatchGuard watch2 = setWatchWithGuard()) { - tree.createNode("/a/a/e"); - assertFired(watch1); - readAssertChildren("/a/b", new String[]{}); - tree.createNode("/a/b/e"); - assertFired(watch2); - } - } - } - - @Test - public void sequentialWatch() throws Exception { - try (TestWatchGuard watch = setWatchWithGuard()) { - readAssertChildren("/a/a", new String[]{"a", "b"}); - tree.removeNode("/a/a/a"); - assertFired(watch); - } - try (TestWatchGuard watch = setWatchWithGuard()) { - readAssertChildren("/a/a", new String[]{"b"}); - tree.removeNode("/a/a/b"); - assertFired(watch); - } - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestDiskChecker.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestDiskChecker.java deleted file mode 100644 index c7d52878a1b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestDiskChecker.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.util; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.apache.bookkeeper.util.DiskChecker.DiskErrorException; -import org.apache.bookkeeper.util.DiskChecker.DiskOutOfSpaceException; -import org.apache.bookkeeper.util.DiskChecker.DiskWarnThresholdException; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Test to verify {@link DiskChecker}. - * - */ -public class TestDiskChecker { - - DiskChecker diskChecker; - - final List tempDirs = new ArrayList(); - private static final float THRESHOLD = 0.99f; - - @Before - public void setup() throws IOException { - diskChecker = new DiskChecker(THRESHOLD, THRESHOLD); - - // Create at least one file so that target disk will never be empty - File placeHolderDir = IOUtils.createTempDir("DiskCheck", "test-placeholder"); - tempDirs.add(placeHolderDir); - File placeHolder = new File(placeHolderDir, "test"); - FileOutputStream placeHolderStream = new FileOutputStream(placeHolder); - placeHolderStream.write(new byte[100 * 1024]); - placeHolderStream.close(); - } - - @After - public void tearDown() throws Exception { - for (File dir : tempDirs) { - FileUtils.deleteDirectory(dir); - } - tempDirs.clear(); - } - - File createTempDir(String prefix, String suffix) throws IOException { - File dir = IOUtils.createTempDir(prefix, suffix); - tempDirs.add(dir); - return dir; - } - - /** - * Check the disk full. - */ - @Test(expected = DiskOutOfSpaceException.class) - public void testCheckDiskFull() throws IOException { - File file = createTempDir("DiskCheck", "test"); - long usableSpace = file.getUsableSpace(); - long totalSpace = file.getTotalSpace(); - float threshold = minMaxThreshold((1f - ((float) usableSpace / (float) totalSpace)) - (1.0f - THRESHOLD)); - - diskChecker.setDiskSpaceThreshold(threshold, threshold); - diskChecker.checkDiskFull(file); - } - - @Test(expected = DiskWarnThresholdException.class) - public void testDiskWarnThresholdException() throws IOException { - File file = createTempDir("DiskCheck", "test"); - long usableSpace = file.getUsableSpace(); - long totalSpace = file.getTotalSpace(); - float diskSpaceThreshold = minMaxThreshold((1f - ((float) usableSpace / (float) totalSpace)) * 1.5f); - float diskWarnThreshold = minMaxThreshold((1f - ((float) usableSpace / (float) totalSpace)) * 0.5f); - - diskChecker.setDiskSpaceThreshold(diskSpaceThreshold, diskWarnThreshold); - diskChecker.checkDiskFull(file); - } - - /** - * Check disk full on non exist file. in this case it should check for - * parent file. - */ - @Test(expected = DiskOutOfSpaceException.class) - public void testCheckDiskFullOnNonExistFile() throws IOException { - File file = createTempDir("DiskCheck", "test"); - long usableSpace = file.getUsableSpace(); - long totalSpace = file.getTotalSpace(); - float threshold = minMaxThreshold((1f - ((float) usableSpace / (float) totalSpace)) * 0.5f); - diskChecker.setDiskSpaceThreshold(threshold, threshold); - assertTrue(file.delete()); - diskChecker.checkDiskFull(file); - } - - /** - * Check disk error for file. - */ - @Test(expected = DiskErrorException.class) - public void testCheckDiskErrorForFile() throws Exception { - File parent = createTempDir("DiskCheck", "test"); - File child = File.createTempFile("DiskCheck", "test", parent); - diskChecker.checkDir(child); - } - - /** - * Check disk error for valid dir. - */ - @Test - public void testCheckDiskErrorForDir() throws Exception { - File parent = createTempDir("DiskCheck", "test"); - File child = File.createTempFile("DiskCheck", "test", parent); - child.delete(); - child.mkdir(); - diskChecker.checkDir(child); - } - - private static float minMaxThreshold(float threshold) { - final float minThreshold = 0.0000001f; - final float maxThreshold = 0.999999f; - - threshold = Math.min(threshold, maxThreshold); - threshold = Math.max(threshold, minThreshold); - return threshold; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestHardLink.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestHardLink.java deleted file mode 100644 index 75f6cf502d8..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestHardLink.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.util; - -import java.io.File; -import java.io.IOException; -import java.util.UUID; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - - -public class TestHardLink { - - private File tempDir; - - @Before - public void setup() throws IOException { - // Create at least one file so that target disk will never be empty - tempDir = IOUtils.createTempDir("TestHardLink", "test-hardlink"); - } - - @After - public void tearDown() throws IOException { - FileUtils.deleteDirectory(tempDir); - } - - private void verifyHardLink(File origin, File linkedOrigin) throws IOException { - Assert.assertTrue(origin.exists()); - Assert.assertFalse(linkedOrigin.exists()); - - HardLink.createHardLink(origin, linkedOrigin); - - Assert.assertTrue(origin.exists()); - Assert.assertTrue(linkedOrigin.exists()); - - // when delete origin file it should be success and not exist. - origin.delete(); - Assert.assertFalse(origin.exists()); - Assert.assertTrue(linkedOrigin.exists()); - } - - @Test - public void testHardLink() throws IOException { - String uuidSuffix = UUID.randomUUID().toString(); - - // prepare file - File origin = new File(tempDir, "originFile." + uuidSuffix); - File linkedOrigin = new File(tempDir, "linkedOrigin." + uuidSuffix); - origin.createNewFile(); - - // disable jdk api link first - HardLink.enableJdkLinkApi(false); - verifyHardLink(origin, linkedOrigin); - - // prepare file - File jdkorigin = new File(tempDir, "jdkoriginFile." + uuidSuffix); - File jdklinkedOrigin = new File(tempDir, "jdklinkedOrigin." + uuidSuffix); - jdkorigin.createNewFile(); - - // enable jdk api link - HardLink.enableJdkLinkApi(true); - verifyHardLink(jdkorigin, jdklinkedOrigin); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestUtils.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestUtils.java deleted file mode 100644 index 38755c884ad..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestUtils.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.util; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.function.BooleanSupplier; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.net.BookieId; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; - -/** - * Test utilities. - */ -@Slf4j -public final class TestUtils { - - private TestUtils() {} - - public static String buildStatsCounterPathFromBookieID(BookieId bookieId) { - return bookieId.toString().replace('.', '_').replace('-', '_').replace(":", "_"); - } - - public static boolean hasAllLogFiles(File ledgerDirectory, Integer... logsId) { - Set logs = findEntryLogFileIds(ledgerDirectory); - return logs.containsAll(Arrays.asList(logsId)); - } - - public static boolean hasNoneLogFiles(File ledgerDirectory, Integer... logsId) { - Set logs = findEntryLogFileIds(ledgerDirectory); - return Arrays.stream(logsId).noneMatch(logs::contains); - } - - public static boolean hasLogFiles(File ledgerDirectory, boolean partial, Integer... logsId) { - boolean result = !partial; - Set logs = findEntryLogFileIds(ledgerDirectory); - for (Integer logId : logsId) { - boolean exist = logs.contains(logId); - if ((partial && exist) - || (!partial && !exist)) { - return !result; - } - } - return result; - } - - private static Set findEntryLogFileIds(File ledgerDirectory) { - Set logs = new HashSet<>(); - for (File file : BookieImpl.getCurrentDirectory(ledgerDirectory).listFiles()) { - if (file.isFile()) { - String name = file.getName(); - if (!name.endsWith(".log")) { - continue; - } - logs.add(Integer.parseInt(name.split("\\.")[0], 16)); - } - } - return logs; - } - - public static void waitUntilLacUpdated(ReadHandle rh, long newLac) throws Exception { - long lac = rh.getLastAddConfirmed(); - while (lac < newLac) { - TimeUnit.MILLISECONDS.sleep(20); - lac = rh.readLastAddConfirmed(); - } - } - - public static long waitUntilExplicitLacUpdated(LedgerHandle rh, long newLac) throws Exception { - long lac; - while ((lac = rh.readExplicitLastConfirmed()) < newLac) { - TimeUnit.MILLISECONDS.sleep(20); - } - return lac; - } - - public static void assertEventuallyTrue(String description, BooleanSupplier predicate) throws Exception { - assertEventuallyTrue(description, predicate, 10, TimeUnit.SECONDS); - } - - public static void assertEventuallyTrue(String description, BooleanSupplier predicate, - long duration, TimeUnit unit) throws Exception { - long iterations = unit.toMillis(duration) / 100; - for (int i = 0; i < iterations && !predicate.getAsBoolean(); i++) { - Thread.sleep(100); - } - Assert.assertTrue(description, predicate.getAsBoolean()); - } - - public static int countNumOfFiles(File[] folderNames, String... extensions) { - int count = 0; - for (int i = 0; i < folderNames.length; i++) { - Collection filesCollection = FileUtils.listFiles(folderNames[i], extensions, true); - count += filesCollection.size(); - } - return count; - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZeroBuffer.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZeroBuffer.java deleted file mode 100644 index 962f9209ef0..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZeroBuffer.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util; - -import java.nio.ByteBuffer; -import java.util.Random; -import org.junit.Assert; -import org.junit.Test; - -/** - * Testcases for ZeroBuffer. - */ -public class TestZeroBuffer { - - @Test - public void testPut() { - ByteBuffer testBuffer; - byte[] testBufferArray; - Random rand = new Random(); - - // Test1 - trying ZeroBuffer.put on small sized TestBuffer - testBuffer = ByteBuffer.allocate(5); - testBufferArray = testBuffer.array(); - testBufferArray[4] = 7; - Assert.assertFalse("Test1 - It is supposed to contain non-zero byte", isFilledWithZeros(testBufferArray, 0, 5)); - ZeroBuffer.put(testBuffer); - Assert.assertTrue("Test1 - After calling, ZeroBuffer.put There aren't supposed to be non-zero bytes", - isFilledWithZeros(testBufferArray, 0, 5)); - - // Test2 - trying ZeroBuffer.put on 64*1024 sized TestBuffer - testBuffer = ByteBuffer.allocate(64 * 1024); - testBufferArray = testBuffer.array(); - rand.nextBytes(testBufferArray); - Assert.assertFalse("Test2 - It is supposed to contain random non-zero bytes", - isFilledWithZeros(testBufferArray, 0, 64 * 1024)); - ZeroBuffer.put(testBuffer); - Assert.assertTrue("Test2 - After calling, ZeroBuffer.put There aren't supposed to be non-zero bytes", - isFilledWithZeros(testBufferArray, 0, 64 * 1024)); - - // Test3 - trying ZeroBuffer.put on portion (64*1024) of large sized - // TestBuffer (256*1024) - testBuffer = ByteBuffer.allocate(256 * 1024); - testBufferArray = testBuffer.array(); - rand.nextBytes(testBufferArray); - Assert.assertFalse("Test3 - It is supposed to contain random non-zero bytes", - isFilledWithZeros(testBufferArray, 64 * 1024, 64 * 1024)); - testBuffer.position(64 * 1024); - ZeroBuffer.put(testBuffer, 64 * 1024); - Assert.assertTrue( - "Test3 - After calling, ZeroBuffer.put There aren't supposed to be non-zero bytes " - + "in the particular section", isFilledWithZeros(testBufferArray, 64 * 1024, 64 * 1024)); - Assert.assertFalse("Test3 - After calling, ZeroBuffer.put other sections shouldnt be touched", - isFilledWithZeros(testBufferArray, 0, 64 * 1024)); - Assert.assertFalse("Test3 - After calling, ZeroBuffer.put other sections shouldnt be touched", - isFilledWithZeros(testBufferArray, 128 * 1024, 128 * 1024)); - } - - @Test - public void testReadOnlyBuffer() { - ByteBuffer testReadOnlyBuffer; - byte[] testBufferArray; - - // Test1 - trying ZeroBuffer.readOnlyBuffer for small size - testReadOnlyBuffer = ZeroBuffer.readOnlyBuffer(5); - Assert.assertTrue( - "Test1 - ReadOnlyBuffer should have remaining 5 bytes but it has " + testReadOnlyBuffer.remaining(), - testReadOnlyBuffer.remaining() == 5); - testBufferArray = new byte[5]; - testReadOnlyBuffer.get(testBufferArray); - Assert.assertTrue("Test1 - supposed to contain only zero bytes", isFilledWithZeros(testBufferArray, 0, 5)); - - // Test2 - trying ZeroBuffer.readOnlyBuffer for 64*1024 - testReadOnlyBuffer = ZeroBuffer.readOnlyBuffer(64 * 1024); - Assert.assertTrue("Test2 - ReadOnlyBuffer should have remaining 64*1024 bytes but it has " - + testReadOnlyBuffer.remaining(), testReadOnlyBuffer.remaining() == 64 * 1024); - testBufferArray = new byte[64 * 1024]; - testReadOnlyBuffer.get(testBufferArray); - Assert.assertTrue("Test2 - supposed to contain only zero bytes", - isFilledWithZeros(testBufferArray, 0, 64 * 1024)); - - // Test3 - trying ZeroBuffer.readOnlyBuffer for > 64*1024 - testReadOnlyBuffer = ZeroBuffer.readOnlyBuffer(128 * 1024); - Assert.assertTrue("Test3 - ReadOnlyBuffer should have remaining 128*1024 bytes but it has " - + testReadOnlyBuffer.remaining(), testReadOnlyBuffer.remaining() == 128 * 1024); - testBufferArray = new byte[128 * 1024]; - testReadOnlyBuffer.get(testBufferArray); - Assert.assertTrue("Test3 - supposed to contain only zero bytes", - isFilledWithZeros(testBufferArray, 0, 128 * 1024)); - } - - boolean isFilledWithZeros(byte[] byteArray, int start, int length) { - for (int i = start; i < (start + length); i++) { - if (byteArray[i] != 0) { - return false; - } - } - return true; - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZkUtils.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZkUtils.java deleted file mode 100644 index e52cf467ddc..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZkUtils.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util; - -import java.io.IOException; -import junit.framework.TestCase; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test ZooKeeper utilities. - */ -public class TestZkUtils extends TestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestZkUtils.class); - - // ZooKeeper related variables - protected ZooKeeperUtil zkUtil = new ZooKeeperUtil(); - - @Before - @Override - public void setUp() throws Exception { - logger.info("Setting up test {}.", getName()); - zkUtil.startCluster(); - } - - @After - @Override - public void tearDown() throws Exception { - zkUtil.killCluster(); - logger.info("Teared down test {}.", getName()); - } - - @Test - public void testAsyncCreateAndDeleteFullPathOptimistic() throws IOException, KeeperException, InterruptedException { - ZooKeeper zkc = new ZooKeeper(zkUtil.getZooKeeperConnectString(), 10000, null); - /* - * "/ledgers/available" is already created in ZooKeeperUtil.startServer - */ - String ledgerZnodePath = "/ledgers/000/000/000/001"; - ZkUtils.createFullPathOptimistic(zkc, ledgerZnodePath, "data".getBytes(), Ids.OPEN_ACL_UNSAFE, - CreateMode.PERSISTENT); - assertTrue(ledgerZnodePath + " zNode should exist", null != zkc.exists(ledgerZnodePath, false)); - - ledgerZnodePath = "/ledgers/000/000/000/002"; - ZkUtils.createFullPathOptimistic(zkc, ledgerZnodePath, "data".getBytes(), Ids.OPEN_ACL_UNSAFE, - CreateMode.PERSISTENT); - assertTrue(ledgerZnodePath + " zNode should exist", null != zkc.exists(ledgerZnodePath, false)); - - ZkUtils.deleteFullPathOptimistic(zkc, ledgerZnodePath, -1); - assertTrue(ledgerZnodePath + " zNode should not exist, since it is deleted", - null == zkc.exists(ledgerZnodePath, false)); - - ledgerZnodePath = "/ledgers/000/000/000/001"; - assertTrue(ledgerZnodePath + " zNode should exist", null != zkc.exists(ledgerZnodePath, false)); - ZkUtils.deleteFullPathOptimistic(zkc, ledgerZnodePath, -1); - assertTrue(ledgerZnodePath + " zNode should not exist, since it is deleted", - null == zkc.exists(ledgerZnodePath, false)); - assertTrue("/ledgers/000" + " zNode should not exist, since it should be deleted recursively", - null == zkc.exists(ledgerZnodePath, false)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashMapTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashMapTest.java deleted file mode 100644 index f1372b28944..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashMapTest.java +++ /dev/null @@ -1,699 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util.collections; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.LongFunction; -import org.junit.Test; - -/** - * Test the ConcurrentLongHashMap class. - */ -public class ConcurrentLongHashMapTest { - - @Test - public void testConstructor() { - try { - ConcurrentLongHashMap.newBuilder() - .expectedItems(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongHashMap.newBuilder() - .expectedItems(4) - .concurrencyLevel(8) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void testReduceUnnecessaryExpansions() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .build(); - assertNull(map.put(1, "v1")); - assertNull(map.put(2, "v2")); - assertNull(map.put(3, "v3")); - assertNull(map.put(4, "v4")); - - assertTrue(map.remove(1, "v1")); - assertTrue(map.remove(2, "v2")); - assertTrue(map.remove(3, "v3")); - assertTrue(map.remove(4, "v4")); - - assertEquals(0, map.getUsedBucketCount()); - } - - @Test - public void testClear() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertNull(map.put(1, "v1")); - assertNull(map.put(2, "v2")); - assertNull(map.put(3, "v3")); - - assertTrue(map.capacity() == 8); - map.clear(); - assertTrue(map.capacity() == 4); - } - - private void addSpecifyIncrement(ConcurrentLongHashMap mkc, int start, int end) { - for (int i = start; i <= end; i++) { - assertNull(mkc.put(i, ("comment:" + i).getBytes(UTF_8))); - } - } - - private void removeSpecifyIncrement(ConcurrentLongHashMap mkc, int start, int end) { - for (int i = end; i >= start; i--) { - assertNotNull(mkc.remove(i)); - } - } - - @Test - public void testAutoShrinkWithByte() { - final int defaultExpectedItems = 256; - final int defaultConcurrencyLevel = 16; - final float defaultExpandFactor = 2; - final float defaultShrinkFactor = 2; - - ConcurrentLongHashMap mkc = ConcurrentLongHashMap.newBuilder().autoShrink(true).build(); - assertTrue(mkc.capacity() == defaultExpectedItems * 2); - - addSpecifyIncrement(mkc, 1, defaultExpectedItems * 2); - // expand hashmap - assertTrue(mkc.capacity() == defaultExpectedItems * 2 - + defaultConcurrencyLevel * defaultExpandFactor * 15); - - removeSpecifyIncrement(mkc, 220, defaultExpectedItems * 2); - // shrink hashmap - assertTrue(mkc.capacity() == defaultExpectedItems * 2 - + defaultConcurrencyLevel * defaultExpandFactor * 15 - defaultConcurrencyLevel * defaultShrinkFactor); - } - - @Test - public void testExpandAndShrink() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertNull(map.put(1, "v1")); - assertNull(map.put(2, "v2")); - assertNull(map.put(3, "v3")); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1, "v1")); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2, "v2")); - // shrink hashmap - assertTrue(map.capacity() == 4); - - // expand hashmap - assertNull(map.put(4, "v4")); - assertNull(map.put(5, "v5")); - assertTrue(map.capacity() == 8); - - //verify that the map does not keep shrinking at every remove() operation - assertNull(map.put(6, "v6")); - assertTrue(map.remove(6, "v6")); - assertTrue(map.capacity() == 8); - } - - @Test - public void testExpandShrinkAndClear() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - final long initCapacity = map.capacity(); - assertTrue(map.capacity() == 4); - assertNull(map.put(1, "v1")); - assertNull(map.put(2, "v2")); - assertNull(map.put(3, "v3")); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1, "v1")); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2, "v2")); - // shrink hashmap - assertTrue(map.capacity() == 4); - - assertTrue(map.remove(3, "v3")); - // Will not shrink the hashmap again because shrink capacity is less than initCapacity - // current capacity is equal than the initial capacity - assertTrue(map.capacity() == initCapacity); - map.clear(); - // after clear, because current capacity is equal than the initial capacity, so not shrinkToInitCapacity - assertTrue(map.capacity() == initCapacity); - } - - @Test - public void simpleInsertions() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(16) - .build(); - - assertTrue(map.isEmpty()); - assertNull(map.put(1, "one")); - assertFalse(map.isEmpty()); - - assertNull(map.put(2, "two")); - assertNull(map.put(3, "three")); - - assertEquals(map.size(), 3); - - assertEquals(map.get(1), "one"); - assertEquals(map.size(), 3); - - assertEquals(map.remove(1), "one"); - assertEquals(map.size(), 2); - assertEquals(map.get(1), null); - assertEquals(map.get(5), null); - assertEquals(map.size(), 2); - - assertNull(map.put(1, "one")); - assertEquals(map.size(), 3); - assertEquals(map.put(1, "uno"), "one"); - assertEquals(map.size(), 3); - } - - @Test - public void testRemove() { - ConcurrentLongHashMap map = - ConcurrentLongHashMap.newBuilder().build(); - - assertTrue(map.isEmpty()); - assertNull(map.put(1, "one")); - assertFalse(map.isEmpty()); - - assertFalse(map.remove(0, "zero")); - assertFalse(map.remove(1, "uno")); - - assertFalse(map.isEmpty()); - assertTrue(map.remove(1, "one")); - assertTrue(map.isEmpty()); - } - - @Test - public void testRemoveIf() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - map.put(1L, "one"); - map.put(2L, "two"); - map.put(3L, "three"); - map.put(4L, "four"); - - map.removeIf((k, v) -> k < 3); - assertFalse(map.containsKey(1L)); - assertFalse(map.containsKey(2L)); - assertTrue(map.containsKey(3L)); - assertTrue(map.containsKey(4L)); - assertEquals(2, map.size()); - } - - @Test - public void testNegativeUsedBucketCount() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - map.put(0, "zero"); - assertEquals(1, map.getUsedBucketCount()); - map.put(0, "zero1"); - assertEquals(1, map.getUsedBucketCount()); - map.remove(0); - assertEquals(0, map.getUsedBucketCount()); - map.remove(0); - assertEquals(0, map.getUsedBucketCount()); - } - - @Test - public void testRehashing() { - int n = 16; - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n; i++) { - map.put(i, i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void testRehashingWithDeletes() { - int n = 16; - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n / 2; i++) { - map.put(i, i); - } - - for (int i = 0; i < n / 2; i++) { - map.remove(i); - } - - for (int i = n; i < (2 * n); i++) { - map.put(i, i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void concurrentInsertions() throws Throwable { - ConcurrentLongHashMap map = - ConcurrentLongHashMap.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - String value = "value"; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.put(key, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void concurrentInsertionsAndReads() throws Throwable { - ConcurrentLongHashMap map = - ConcurrentLongHashMap.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - String value = "value"; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.put(key, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void stressConcurrentInsertionsAndReads() throws Throwable { - ConcurrentLongHashMap map = - ConcurrentLongHashMap.newBuilder().expectedItems(4).concurrencyLevel(1).build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int writeThreads = 16; - final int readThreads = 16; - final int n = 1_000_000; - String value = "value"; - - CyclicBarrier barrier = new CyclicBarrier(writeThreads + readThreads); - List> futures = new ArrayList<>(); - - - for (int i = 0; i < writeThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(threadIdx); - - try { - barrier.await(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.put(key, value); - } - })); - } - - for (int i = 0; i < readThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(threadIdx); - - try { - barrier.await(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.get(key); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * writeThreads); - - executor.shutdown(); - } - - @Test - public void testIteration() { - ConcurrentLongHashMap map = - ConcurrentLongHashMap.newBuilder().build(); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0, "zero"); - - assertEquals(map.keys(), Lists.newArrayList(0L)); - assertEquals(map.values(), Lists.newArrayList("zero")); - - map.remove(0); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0, "zero"); - map.put(1, "one"); - map.put(2, "two"); - - List keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(0L, 1L, 2L)); - - List values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList("one", "two", "zero")); - - map.put(1, "uno"); - - keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(0L, 1L, 2L)); - - values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList("two", "uno", "zero")); - - map.clear(); - assertTrue(map.isEmpty()); - } - - @Test - public void testHashConflictWithDeletion() { - final int buckets = 16; - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(buckets) - .concurrencyLevel(1) - .build(); - - // Pick 2 keys that fall into the same bucket - long key1 = 1; - long key2 = 27; - - int bucket1 = ConcurrentLongHashMap.signSafeMod(ConcurrentLongHashMap.hash(key1), buckets); - int bucket2 = ConcurrentLongHashMap.signSafeMod(ConcurrentLongHashMap.hash(key2), buckets); - assertEquals(bucket1, bucket2); - - assertEquals(map.put(key1, "value-1"), null); - assertEquals(map.put(key2, "value-2"), null); - assertEquals(map.size(), 2); - - assertEquals(map.remove(key1), "value-1"); - assertEquals(map.size(), 1); - - assertEquals(map.put(key1, "value-1-overwrite"), null); - assertEquals(map.size(), 2); - - assertEquals(map.remove(key1), "value-1-overwrite"); - assertEquals(map.size(), 1); - - assertEquals(map.put(key2, "value-2-overwrite"), "value-2"); - assertEquals(map.get(key2), "value-2-overwrite"); - - assertEquals(map.size(), 1); - assertEquals(map.remove(key2), "value-2-overwrite"); - assertTrue(map.isEmpty()); - } - - @Test - public void testPutIfAbsent() { - ConcurrentLongHashMap map = - ConcurrentLongHashMap.newBuilder().build(); - assertEquals(map.putIfAbsent(1, "one"), null); - assertEquals(map.get(1), "one"); - - assertEquals(map.putIfAbsent(1, "uno"), "one"); - assertEquals(map.get(1), "one"); - } - - @Test - public void testComputeIfAbsent() { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - AtomicInteger counter = new AtomicInteger(); - LongFunction provider = new LongFunction() { - public Integer apply(long key) { - return counter.getAndIncrement(); - } - }; - - assertEquals(map.computeIfAbsent(0, provider).intValue(), 0); - assertEquals(map.get(0).intValue(), 0); - - assertEquals(map.computeIfAbsent(1, provider).intValue(), 1); - assertEquals(map.get(1).intValue(), 1); - - assertEquals(map.computeIfAbsent(1, provider).intValue(), 1); - assertEquals(map.get(1).intValue(), 1); - - assertEquals(map.computeIfAbsent(2, provider).intValue(), 2); - assertEquals(map.get(2).intValue(), 2); - } - - static final int Iterations = 1; - static final int ReadIterations = 100; - static final int N = 1_000_000; - - public void benchConcurrentLongHashMap() throws Exception { - // public static void main(String args[]) { - ConcurrentLongHashMap map = ConcurrentLongHashMap.newBuilder() - .expectedItems(N) - .concurrencyLevel(1) - .build(); - - for (long i = 0; i < Iterations; i++) { - for (int j = 0; j < N; j++) { - map.put(i, "value"); - } - - for (long h = 0; h < ReadIterations; h++) { - for (int j = 0; j < N; j++) { - map.get(i); - } - } - - for (int j = 0; j < N; j++) { - map.remove(i); - } - } - } - - public void benchConcurrentHashMap() throws Exception { - ConcurrentHashMap map = new ConcurrentHashMap(N, 0.66f, 1); - - for (long i = 0; i < Iterations; i++) { - for (int j = 0; j < N; j++) { - map.put(i, "value"); - } - - for (long h = 0; h < ReadIterations; h++) { - for (int j = 0; j < N; j++) { - map.get(i); - } - } - - for (int j = 0; j < N; j++) { - map.remove(i); - } - } - } - - void benchHashMap() throws Exception { - HashMap map = new HashMap(N, 0.66f); - - for (long i = 0; i < Iterations; i++) { - for (int j = 0; j < N; j++) { - map.put(i, "value"); - } - - for (long h = 0; h < ReadIterations; h++) { - for (int j = 0; j < N; j++) { - map.get(i); - } - } - - for (int j = 0; j < N; j++) { - map.remove(i); - } - } - } - - public static void main(String[] args) throws Exception { - ConcurrentLongHashMapTest t = new ConcurrentLongHashMapTest(); - - long start = System.nanoTime(); - // t.benchHashMap(); - long end = System.nanoTime(); - - System.out.println("HM: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); - - start = System.nanoTime(); - t.benchConcurrentHashMap(); - end = System.nanoTime(); - - System.out.println("CHM: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); - - start = System.nanoTime(); - // t.benchConcurrentLongHashMap(); - end = System.nanoTime(); - - System.out.println("CLHM: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashSetTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashSetTest.java deleted file mode 100644 index 2c28e882930..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashSetTest.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import org.junit.Test; - -/** - * Test the ConcurrentLongHashSet class. - */ -@SuppressWarnings("deprecation") -public class ConcurrentLongHashSetTest { - - @Test - public void testConstructor() { - try { - ConcurrentLongHashSet.newBuilder().concurrencyLevel(0).build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongHashSet.newBuilder().expectedItems(16).concurrencyLevel(0).build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongHashSet.newBuilder().expectedItems(4).concurrencyLevel(8).build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void simpleInsertions() { - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder() - .expectedItems(16) - .build(); - - assertTrue(set.isEmpty()); - assertTrue(set.add(1)); - assertFalse(set.isEmpty()); - - assertTrue(set.add(2)); - assertTrue(set.add(3)); - - assertEquals(set.size(), 3); - - assertTrue(set.contains(1)); - assertEquals(set.size(), 3); - - assertTrue(set.remove(1)); - assertEquals(set.size(), 2); - assertFalse(set.contains(1)); - assertFalse(set.contains(5)); - assertEquals(set.size(), 2); - - assertTrue(set.add(1)); - assertEquals(set.size(), 3); - assertFalse(set.add(1)); - assertEquals(set.size(), 3); - } - - @Test - public void testReduceUnnecessaryExpansions() { - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .build(); - assertTrue(set.add(1)); - assertTrue(set.add(2)); - assertTrue(set.add(3)); - assertTrue(set.add(4)); - - assertTrue(set.remove(1)); - assertTrue(set.remove(2)); - assertTrue(set.remove(3)); - assertTrue(set.remove(4)); - - assertEquals(0, set.getUsedBucketCount()); - } - - @Test - public void testRemove() { - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder().build(); - - assertTrue(set.isEmpty()); - assertTrue(set.add(1)); - assertFalse(set.isEmpty()); - - assertFalse(set.remove(0)); - assertFalse(set.isEmpty()); - assertTrue(set.remove(1)); - assertTrue(set.isEmpty()); - } - - @Test - public void testRehashing() { - int n = 16; - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(set.capacity(), n); - assertEquals(set.size(), 0); - - for (int i = 0; i < n; i++) { - set.add(i); - } - - assertEquals(set.capacity(), 2 * n); - assertEquals(set.size(), n); - } - - @Test - public void testRehashingWithDeletes() { - int n = 16; - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(set.capacity(), n); - assertEquals(set.size(), 0); - - for (int i = 0; i < n / 2; i++) { - set.add(i); - } - - for (int i = 0; i < n / 2; i++) { - set.remove(i); - } - - for (int i = n; i < (2 * n); i++) { - set.add(i); - } - - assertEquals(set.capacity(), 2 * n); - assertEquals(set.size(), n); - } - - @Test - public void concurrentInsertions() throws Throwable { - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = Math.abs(random.nextLong()); - // Ensure keys are unique - key -= key % (threadIdx + 1); - - set.add(key); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(set.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void concurrentInsertionsAndReads() throws Throwable { - ConcurrentLongHashSet map = ConcurrentLongHashSet.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = Math.abs(random.nextLong()); - // Ensure keys are unique - key -= key % (threadIdx + 1); - - map.add(key); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void testClear() { - ConcurrentLongHashSet map = ConcurrentLongHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertTrue(map.add(1)); - assertTrue(map.add(2)); - assertTrue(map.add(3)); - - assertTrue(map.capacity() == 8); - map.clear(); - assertTrue(map.capacity() == 4); - } - - @Test - public void testExpandAndShrink() { - ConcurrentLongHashSet map = ConcurrentLongHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertTrue(map.add(1)); - assertTrue(map.add(2)); - assertTrue(map.add(3)); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1)); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2)); - // shrink hashmap - assertTrue(map.capacity() == 4); - - // expand hashmap - assertTrue(map.add(4)); - assertTrue(map.add(5)); - assertTrue(map.capacity() == 8); - - //verify that the map does not keep shrinking at every remove() operation - assertTrue(map.add(6)); - assertTrue(map.remove(6)); - assertTrue(map.capacity() == 8); - } - - @Test - public void testExpandShrinkAndClear() { - ConcurrentLongHashSet map = ConcurrentLongHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - final long initCapacity = map.capacity(); - assertTrue(map.capacity() == 4); - - assertTrue(map.add(1)); - assertTrue(map.add(2)); - assertTrue(map.add(3)); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1)); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2)); - // shrink hashmap - assertTrue(map.capacity() == 4); - - assertTrue(map.remove(3)); - // Will not shrink the hashmap again because shrink capacity is less than initCapacity - // current capacity is equal than the initial capacity - assertTrue(map.capacity() == initCapacity); - map.clear(); - // after clear, because current capacity is equal than the initial capacity, so not shrinkToInitCapacity - assertTrue(map.capacity() == initCapacity); - } - - @Test - public void testIteration() { - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder().build(); - - assertEquals(set.items(), Collections.emptySet()); - - set.add(0L); - - assertEquals(set.items(), Sets.newHashSet(0L)); - - set.remove(0L); - - assertEquals(set.items(), Collections.emptySet()); - - set.add(0L); - set.add(1L); - set.add(2L); - - List values = Lists.newArrayList(set.items()); - Collections.sort(values); - assertEquals(values, Lists.newArrayList(0L, 1L, 2L)); - - set.clear(); - assertTrue(set.isEmpty()); - } - - @Test - public void testHashConflictWithDeletion() { - final int buckets = 16; - ConcurrentLongHashSet set = ConcurrentLongHashSet.newBuilder() - .expectedItems(buckets) - .concurrencyLevel(1) - .build(); - - // Pick 2 keys that fall into the same bucket - long key1 = 1; - long key2 = 27; - - int bucket1 = ConcurrentOpenHashSet.signSafeMod(ConcurrentOpenHashSet.hash(key1), buckets); - int bucket2 = ConcurrentOpenHashSet.signSafeMod(ConcurrentOpenHashSet.hash(key2), buckets); - assertEquals(bucket1, bucket2); - - assertTrue(set.add(key1)); - assertTrue(set.add(key2)); - assertEquals(set.size(), 2); - - assertTrue(set.remove(key1)); - assertEquals(set.size(), 1); - - assertTrue(set.add(key1)); - assertEquals(set.size(), 2); - - assertTrue(set.remove(key1)); - assertEquals(set.size(), 1); - - assertFalse(set.add(key2)); - assertTrue(set.contains(key2)); - - assertEquals(set.size(), 1); - assertTrue(set.remove(key2)); - assertTrue(set.isEmpty()); - } - - @Test - public void testSizeInBytes() { - ConcurrentLongHashSet set = new ConcurrentLongHashSet(4, 2); - assertEquals(64, set.sizeInBytes()); - set.add(1); - assertEquals(64, set.sizeInBytes()); - set.add(2); - assertEquals(64, set.sizeInBytes()); - set.add(3); - assertEquals(64, set.sizeInBytes()); - set.add(4); - assertEquals(96, set.sizeInBytes()); - set.add(5); - assertEquals(96, set.sizeInBytes()); - set.add(6); - assertEquals(128, set.sizeInBytes()); - set.add(7); - assertEquals(128, set.sizeInBytes()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongHashMapTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongHashMapTest.java deleted file mode 100644 index aca46946746..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongHashMapTest.java +++ /dev/null @@ -1,639 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.bookkeeper.util.collections.ConcurrentLongLongHashMap.LongLongFunction; -import org.junit.Test; - -/** - * Test the ConcurrentLongLongHashMap class. - */ -@SuppressWarnings("deprecation") -public class ConcurrentLongLongHashMapTest { - - @Test - public void testConstructor() { - try { - ConcurrentLongLongHashMap.newBuilder() - .expectedItems(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongLongHashMap.newBuilder() - .expectedItems(4) - .concurrencyLevel(8) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void simpleInsertions() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .build(); - - assertTrue(map.isEmpty()); - assertEquals(map.put(1, 11), -1); - assertFalse(map.isEmpty()); - - assertEquals(map.put(2, 22), -1); - assertEquals(map.put(3, 33), -1); - - assertEquals(map.size(), 3); - - assertEquals(map.get(1), 11); - assertEquals(map.size(), 3); - - assertEquals(map.remove(1), 11); - assertEquals(map.size(), 2); - assertEquals(map.get(1), -1); - assertEquals(map.get(5), -1); - assertEquals(map.size(), 2); - - assertEquals(map.put(1, 11), -1); - assertEquals(map.size(), 3); - assertEquals(map.put(1, 111), 11); - assertEquals(map.size(), 3); - } - - @Test - public void testClear() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertTrue(map.put(1, 1) == -1); - assertTrue(map.put(2, 2) == -1); - assertTrue(map.put(3, 3) == -1); - - assertTrue(map.capacity() == 8); - map.clear(); - assertTrue(map.capacity() == 4); - } - - @Test - public void testExpandAndShrink() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.put(1, 1) == -1); - assertTrue(map.put(2, 2) == -1); - assertTrue(map.put(3, 3) == -1); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1, 1)); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2, 2)); - // shrink hashmap - assertTrue(map.capacity() == 4); - - // expand hashmap - assertTrue(map.put(4, 4) == -1); - assertTrue(map.put(5, 5) == -1); - assertTrue(map.capacity() == 8); - - //verify that the map does not keep shrinking at every remove() operation - assertTrue(map.put(6, 6) == -1); - assertTrue(map.remove(6, 6)); - assertTrue(map.capacity() == 8); - } - - @Test - public void testExpandShrinkAndClear() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - final long initCapacity = map.capacity(); - assertTrue(map.capacity() == 4); - assertTrue(map.put(1, 1) == -1); - assertTrue(map.put(2, 2) == -1); - assertTrue(map.put(3, 3) == -1); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1, 1)); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2, 2)); - // shrink hashmap - assertTrue(map.capacity() == 4); - - assertTrue(map.remove(3, 3)); - // Will not shrink the hashmap again because shrink capacity is less than initCapacity - // current capacity is equal than the initial capacity - assertTrue(map.capacity() == initCapacity); - map.clear(); - // after clear, because current capacity is equal than the initial capacity, so not shrinkToInitCapacity - assertTrue(map.capacity() == initCapacity); - } - - @Test - public void testRemove() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder().build(); - - assertTrue(map.isEmpty()); - assertEquals(map.put(1, 11), -1); - assertFalse(map.isEmpty()); - - assertFalse(map.remove(0, 0)); - assertFalse(map.remove(1, 111)); - - assertFalse(map.isEmpty()); - assertTrue(map.remove(1, 11)); - assertTrue(map.isEmpty()); - } - - @Test - public void testNegativeUsedBucketCount() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - map.put(0, 0); - assertEquals(1, map.getUsedBucketCount()); - map.put(0, 1); - assertEquals(1, map.getUsedBucketCount()); - map.remove(0); - assertEquals(0, map.getUsedBucketCount()); - map.remove(0); - assertEquals(0, map.getUsedBucketCount()); - } - - @Test - public void testRehashing() { - int n = 16; - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n; i++) { - map.put(i, i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void testRehashingWithDeletes() { - int n = 16; - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n / 2; i++) { - map.put(i, i); - } - - for (int i = 0; i < n / 2; i++) { - map.remove(i); - } - - for (int i = n; i < (2 * n); i++) { - map.put(i, i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void concurrentInsertions() throws Throwable { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - long value = 55; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = Math.abs(random.nextLong()); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.put(key, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void concurrentInsertionsAndReads() throws Throwable { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - final long value = 55; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = Math.abs(random.nextLong()); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.put(key, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void testIteration() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder().build(); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0, 0); - - assertEquals(map.keys(), Lists.newArrayList(0L)); - assertEquals(map.values(), Lists.newArrayList(0L)); - - map.remove(0); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0, 0); - map.put(1, 11); - map.put(2, 22); - - List keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(0L, 1L, 2L)); - - List values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList(0L, 11L, 22L)); - - map.put(1, 111); - - keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(0L, 1L, 2L)); - - values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList(0L, 22L, 111L)); - - map.clear(); - assertTrue(map.isEmpty()); - } - - @Test - public void testHashConflictWithDeletion() { - final int buckets = 16; - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(buckets) - .concurrencyLevel(1) - .build(); - - // Pick 2 keys that fall into the same bucket - long key1 = 1; - long key2 = 27; - - int bucket1 = ConcurrentLongLongHashMap.signSafeMod(ConcurrentLongLongHashMap.hash(key1), buckets); - int bucket2 = ConcurrentLongLongHashMap.signSafeMod(ConcurrentLongLongHashMap.hash(key2), buckets); - assertEquals(bucket1, bucket2); - - final long value1 = 1; - final long value2 = 2; - final long value1Overwrite = 3; - final long value2Overwrite = 3; - - assertEquals(map.put(key1, value1), -1); - assertEquals(map.put(key2, value2), -1); - assertEquals(map.size(), 2); - - assertEquals(map.remove(key1), value1); - assertEquals(map.size(), 1); - - assertEquals(map.put(key1, value1Overwrite), -1); - assertEquals(map.size(), 2); - - assertEquals(map.remove(key1), value1Overwrite); - assertEquals(map.size(), 1); - - assertEquals(map.put(key2, value2Overwrite), value2); - assertEquals(map.get(key2), value2Overwrite); - - assertEquals(map.size(), 1); - assertEquals(map.remove(key2), value2Overwrite); - assertTrue(map.isEmpty()); - } - - @Test - public void testPutIfAbsent() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder().build(); - assertEquals(map.putIfAbsent(1, 11), -1); - assertEquals(map.get(1), 11); - - assertEquals(map.putIfAbsent(1, 111), 11); - assertEquals(map.get(1), 11); - } - - @Test - public void testComputeIfAbsent() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - AtomicLong counter = new AtomicLong(); - LongLongFunction provider = new LongLongFunction() { - public long apply(long key) { - return counter.getAndIncrement(); - } - }; - - assertEquals(map.computeIfAbsent(0, provider), 0); - assertEquals(map.get(0), 0); - - assertEquals(map.computeIfAbsent(1, provider), 1); - assertEquals(map.get(1), 1); - - assertEquals(map.computeIfAbsent(1, provider), 1); - assertEquals(map.get(1), 1); - - assertEquals(map.computeIfAbsent(2, provider), 2); - assertEquals(map.get(2), 2); - } - - @Test - public void testAddAndGet() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - assertEquals(map.addAndGet(0, 0), 0); - assertEquals(map.containsKey(0), true); - assertEquals(map.get(0), 0); - - assertEquals(map.containsKey(5), false); - - assertEquals(map.addAndGet(0, 5), 5); - assertEquals(map.get(0), 5); - - assertEquals(map.addAndGet(0, 1), 6); - assertEquals(map.get(0), 6); - - assertEquals(map.addAndGet(0, -2), 4); - assertEquals(map.get(0), 4); - - // Cannot bring to value to negative - try { - map.addAndGet(0, -5); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - assertEquals(map.get(0), 4); - } - - @Test - public void testReduceUnnecessaryExpansions() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .build(); - map.put(1L, 1L); - map.put(2L, 2L); - map.put(3L, 3L); - map.put(4L, 4L); - - map.remove(1L); - map.remove(2L); - map.remove(3L); - map.remove(4L); - assertEquals(0, map.getUsedBucketCount()); - } - - - @Test - public void testRemoveIf() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - map.put(1L, 1L); - map.put(2L, 2L); - map.put(3L, 3L); - map.put(4L, 4L); - - map.removeIf(key -> key < 3); - assertFalse(map.containsKey(1L)); - assertFalse(map.containsKey(2L)); - assertTrue(map.containsKey(3L)); - assertTrue(map.containsKey(4L)); - assertEquals(2, map.size()); - } - - @Test - public void testRemoveIfValue() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - map.put(1L, 1L); - map.put(2L, 2L); - map.put(3L, 1L); - map.put(4L, 2L); - - map.removeIf((key, value) -> value < 2); - assertFalse(map.containsKey(1L)); - assertTrue(map.containsKey(2L)); - assertFalse(map.containsKey(3L)); - assertTrue(map.containsKey(4L)); - assertEquals(2, map.size()); - } - - @Test - public void testIvalidKeys() { - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - try { - map.put(-5, 4); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - map.get(-1); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - map.containsKey(-1); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - map.putIfAbsent(-1, 1); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - map.computeIfAbsent(-1, new LongLongFunction() { - @Override - public long apply(long key) { - return 1; - } - }); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void testAsMap() { - ConcurrentLongLongHashMap lmap = ConcurrentLongLongHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - lmap.put(1, 11); - lmap.put(2, 22); - lmap.put(3, 33); - - Map map = Maps.newTreeMap(); - map.put(1L, 11L); - map.put(2L, 22L); - map.put(3L, 33L); - - assertEquals(map, lmap.asMap()); - } - - @Test - public void testSizeInBytes() { - ConcurrentLongLongHashMap lmap = new ConcurrentLongLongHashMap(4, 2); - assertEquals(128, lmap.sizeInBytes()); - lmap.put(1, 1); - assertEquals(128, lmap.sizeInBytes()); - lmap.put(2, 2); - assertEquals(128, lmap.sizeInBytes()); - lmap.put(3, 3); - assertEquals(128, lmap.sizeInBytes()); - lmap.put(4, 4); - assertEquals(192, lmap.sizeInBytes()); - lmap.put(5, 5); - assertEquals(192, lmap.sizeInBytes()); - lmap.put(6, 6); - assertEquals(256, lmap.sizeInBytes()); - lmap.put(7, 7); - assertEquals(256, lmap.sizeInBytes()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongPairHashMapTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongPairHashMapTest.java deleted file mode 100644 index b13625fcc9b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongPairHashMapTest.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import org.apache.bookkeeper.util.collections.ConcurrentLongLongPairHashMap.LongPair; -import org.junit.Test; - -/** - * Test the concurrent long-long pair hashmap class. - */ -@SuppressWarnings("deprecation") -public class ConcurrentLongLongPairHashMapTest { - - @Test - public void testConstructor() { - try { - ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(4) - .concurrencyLevel(8) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void simpleInsertions() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(16) - .build(); - assertTrue(map.isEmpty()); - assertTrue(map.put(1, 1, 11, 11)); - assertFalse(map.isEmpty()); - - assertTrue(map.put(2, 2, 22, 22)); - assertTrue(map.put(3, 3, 33, 33)); - - assertEquals(map.size(), 3); - - assertEquals(map.get(1, 1), new LongPair(11, 11)); - assertEquals(map.size(), 3); - - assertTrue(map.remove(1, 1)); - assertEquals(map.size(), 2); - assertEquals(map.get(1, 1), null); - assertEquals(map.get(5, 5), null); - assertEquals(map.size(), 2); - - assertTrue(map.put(1, 1, 11, 11)); - assertEquals(map.size(), 3); - assertTrue(map.put(1, 1, 111, 111)); - assertEquals(map.size(), 3); - } - - @Test - public void testRemove() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap - .newBuilder() - .build(); - - assertTrue(map.isEmpty()); - assertTrue(map.put(1, 1, 11, 11)); - assertFalse(map.isEmpty()); - - assertFalse(map.remove(0, 0)); - assertFalse(map.remove(1, 1, 111, 111)); - - assertFalse(map.isEmpty()); - assertTrue(map.remove(1, 1, 11, 11)); - assertTrue(map.isEmpty()); - } - - @Test - public void testClear() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertTrue(map.put(1, 1, 11, 11)); - assertTrue(map.put(2, 2, 22, 22)); - assertTrue(map.put(3, 3, 33, 33)); - - assertTrue(map.capacity() == 8); - map.clear(); - assertTrue(map.capacity() == 4); - } - - @Test - public void testExpandAndShrink() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.put(1, 1, 11, 11)); - assertTrue(map.put(2, 2, 22, 22)); - assertTrue(map.put(3, 3, 33, 33)); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1, 1, 11, 11)); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2, 2, 22, 22)); - // shrink hashmap - assertTrue(map.capacity() == 4); - - // expand hashmap - assertTrue(map.put(4, 4, 44, 44)); - assertTrue(map.put(5, 5, 55, 55)); - assertTrue(map.capacity() == 8); - - //verify that the map does not keep shrinking at every remove() operation - assertTrue(map.put(6, 6, 66, 66)); - assertTrue(map.remove(6, 6, 66, 66)); - assertTrue(map.capacity() == 8); - } - - @Test - public void testExpandShrinkAndClear() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - final long initCapacity = map.capacity(); - assertTrue(map.put(1, 1, 11, 11)); - assertTrue(map.put(2, 2, 22, 22)); - assertTrue(map.put(3, 3, 33, 33)); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove(1, 1, 11, 11)); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove(2, 2, 22, 22)); - // shrink hashmap - assertTrue(map.capacity() == 4); - - assertTrue(map.remove(3, 3, 33, 33)); - // Will not shrink the hashmap again because shrink capacity is less than initCapacity - // current capacity is equal than the initial capacity - assertTrue(map.capacity() == initCapacity); - map.clear(); - // after clear, because current capacity is equal than the initial capacity, so not shrinkToInitCapacity - assertTrue(map.capacity() == initCapacity); - } - - @Test - public void testNegativeUsedBucketCount() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - map.put(0, 0, 0, 0); - assertEquals(1, map.getUsedBucketCount()); - map.put(0, 0, 1, 1); - assertEquals(1, map.getUsedBucketCount()); - map.remove(0, 0); - assertEquals(0, map.getUsedBucketCount()); - map.remove(0, 0); - assertEquals(0, map.getUsedBucketCount()); - } - - @Test - public void testReduceUnnecessaryExpansions() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .mapFillFactor(0.9f) - .build(); - map.put(1, 1, 1, 1); - map.put(2, 2, 2, 2); - map.put(3, 3, 3, 3); - - map.remove(1, 1); - map.remove(2, 2); - map.remove(3, 3); - - assertEquals(0, map.getUsedBucketCount()); - } - - @Test - public void testRehashing() { - int n = 16; - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n; i++) { - map.put(i, i, i, i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void testRehashingWithDeletes() { - int n = 16; - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n / 2; i++) { - map.put(i, i, i, i); - } - - for (int i = 0; i < n / 2; i++) { - map.remove(i, i); - } - - for (int i = n; i < (2 * n); i++) { - map.put(i, i, i, i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void concurrentInsertions() throws Throwable { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - long value = 55; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key1 = Math.abs(random.nextLong()); - // Ensure keys are uniques - key1 -= key1 % (threadIdx + 1); - - long key2 = Math.abs(random.nextLong()); - // Ensure keys are uniques - key2 -= key2 % (threadIdx + 1); - - map.put(key1, key2, value, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void concurrentInsertionsAndReads() throws Throwable { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - final long value = 55; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key1 = Math.abs(random.nextLong()); - // Ensure keys are uniques - key1 -= key1 % (threadIdx + 1); - - long key2 = Math.abs(random.nextLong()); - // Ensure keys are uniques - key2 -= key2 % (threadIdx + 1); - - map.put(key1, key2, value, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void testIteration() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .build(); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0, 0, 0, 0); - - assertEquals(map.keys(), Lists.newArrayList(new LongPair(0, 0))); - assertEquals(map.values(), Lists.newArrayList(new LongPair(0, 0))); - - map.remove(0, 0); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0, 0, 0, 0); - map.put(1, 1, 11, 11); - map.put(2, 2, 22, 22); - - List keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(new LongPair(0, 0), new LongPair(1, 1), new LongPair(2, 2))); - - List values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList(new LongPair(0, 0), new LongPair(11, 11), new LongPair(22, 22))); - - map.put(1, 1, 111, 111); - - keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(new LongPair(0, 0), new LongPair(1, 1), new LongPair(2, 2))); - - values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList(new LongPair(0, 0), new LongPair(22, 22), new LongPair(111, 111))); - - map.clear(); - assertTrue(map.isEmpty()); - } - - @Test - public void testPutIfAbsent() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .build(); - - assertTrue(map.putIfAbsent(1, 1, 11, 11)); - assertEquals(map.get(1, 1), new LongPair(11, 11)); - - assertFalse(map.putIfAbsent(1, 1, 111, 111)); - assertEquals(map.get(1, 1), new LongPair(11, 11)); - } - - @Test - public void testIvalidKeys() { - ConcurrentLongLongPairHashMap map = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - - - try { - map.put(-5, 3, 4, 4); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - map.get(-1, 0); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - map.containsKey(-1, 0); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - map.putIfAbsent(-1, 1, 1, 1); - fail("should have failed"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void testAsMap() { - ConcurrentLongLongPairHashMap lmap = ConcurrentLongLongPairHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - lmap.put(1, 1, 11, 11); - lmap.put(2, 2, 22, 22); - lmap.put(3, 3, 33, 33); - - Map map = Maps.newTreeMap(); - map.put(new LongPair(1, 1), new LongPair(11, 11)); - map.put(new LongPair(2, 2), new LongPair(22, 22)); - map.put(new LongPair(3, 3), new LongPair(33, 33)); - - assertEquals(map, lmap.asMap()); - } - - @Test - public void testSizeInBytes() { - ConcurrentLongLongPairHashMap lmap = new ConcurrentLongLongPairHashMap(4, 2); - assertEquals(256, lmap.sizeInBytes()); - lmap.put(1, 1, 1, 1); - assertEquals(256, lmap.sizeInBytes()); - lmap.put(2, 2, 2, 2); - assertEquals(256, lmap.sizeInBytes()); - lmap.put(3, 3, 3, 3); - assertEquals(256, lmap.sizeInBytes()); - lmap.put(4, 4, 4, 4); - assertEquals(256, lmap.sizeInBytes()); - lmap.put(5, 5, 5, 5); - assertEquals(384, lmap.sizeInBytes()); - lmap.put(6, 6, 6, 6); - assertEquals(512, lmap.sizeInBytes()); - lmap.put(7, 7, 7, 7); - assertEquals(512, lmap.sizeInBytes()); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashMapTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashMapTest.java deleted file mode 100644 index 3ed17edb57a..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashMapTest.java +++ /dev/null @@ -1,625 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiPredicate; -import java.util.function.Function; -import org.junit.Test; - -/** - * Test the concurrent open HashMap class. - */ -public class ConcurrentOpenHashMapTest { - - @Test - public void testConstructor() { - try { - ConcurrentOpenHashMap.newBuilder().expectedItems(0).build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentOpenHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentOpenHashMap.newBuilder() - .expectedItems(4) - .concurrencyLevel(8) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void testReduceUnnecessaryExpansions() { - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .build(); - assertNull(map.put("1", "1")); - assertNull(map.put("2", "2")); - assertNull(map.put("3", "3")); - assertNull(map.put("4", "4")); - - assertEquals(map.remove("1"), "1"); - assertEquals(map.remove("2"), "2"); - assertEquals(map.remove("3"), "3"); - assertEquals(map.remove("4"), "4"); - - assertEquals(0, map.getUsedBucketCount()); - } - - @Test - public void simpleInsertions() { - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(16) - .build(); - - assertTrue(map.isEmpty()); - assertNull(map.put("1", "one")); - assertFalse(map.isEmpty()); - - assertNull(map.put("2", "two")); - assertNull(map.put("3", "three")); - - assertEquals(map.size(), 3); - - assertEquals(map.get("1"), "one"); - assertEquals(map.size(), 3); - - assertEquals(map.remove("1"), "one"); - assertEquals(map.size(), 2); - assertEquals(map.get("1"), null); - assertEquals(map.get("5"), null); - assertEquals(map.size(), 2); - - assertNull(map.put("1", "one")); - assertEquals(map.size(), 3); - assertEquals(map.put("1", "uno"), "one"); - assertEquals(map.size(), 3); - } - - @Test - public void testClear() { - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertNull(map.put("k1", "v1")); - assertNull(map.put("k2", "v2")); - assertNull(map.put("k3", "v3")); - - assertTrue(map.capacity() == 8); - map.clear(); - assertTrue(map.capacity() == 4); - } - - @Test - public void testExpandAndShrink() { - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertNull(map.put("k1", "v1")); - assertNull(map.put("k2", "v2")); - assertNull(map.put("k3", "v3")); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove("k1", "v1")); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove("k2", "v2")); - // shrink hashmap - assertTrue(map.capacity() == 4); - - // expand hashmap - assertNull(map.put("k4", "v4")); - assertNull(map.put("k5", "v5")); - assertTrue(map.capacity() == 8); - - //verify that the map does not keep shrinking at every remove() operation - assertNull(map.put("k6", "v6")); - assertTrue(map.remove("k6", "v6")); - assertTrue(map.capacity() == 8); - } - - @Test - public void testExpandShrinkAndClear() { - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - final long initCapacity = map.capacity(); - assertTrue(map.capacity() == 4); - assertNull(map.put("k1", "v1")); - assertNull(map.put("k2", "v2")); - assertNull(map.put("k3", "v3")); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove("k1", "v1")); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove("k2", "v2")); - // shrink hashmap - assertTrue(map.capacity() == 4); - - assertTrue(map.remove("k3", "v3")); - // Will not shrink the hashmap again because shrink capacity is less than initCapacity - // current capacity is equal than the initial capacity - assertTrue(map.capacity() == initCapacity); - map.clear(); - // after clear, because current capacity is equal than the initial capacity, so not shrinkToInitCapacity - assertTrue(map.capacity() == initCapacity); - } - - @Test - public void testRemove() { - ConcurrentOpenHashMap map = - ConcurrentOpenHashMap.newBuilder().build(); - - assertTrue(map.isEmpty()); - assertNull(map.put("1", "one")); - assertFalse(map.isEmpty()); - - assertFalse(map.remove("0", "zero")); - assertFalse(map.remove("1", "uno")); - - assertFalse(map.isEmpty()); - assertTrue(map.remove("1", "one")); - assertTrue(map.isEmpty()); - } - - @Test - public void testRehashing() { - int n = 16; - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n; i++) { - map.put(Integer.toString(i), i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void testRehashingWithDeletes() { - int n = 16; - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(map.capacity(), n); - assertEquals(map.size(), 0); - - for (int i = 0; i < n / 2; i++) { - map.put(i, i); - } - - for (int i = 0; i < n / 2; i++) { - map.remove(i); - } - - for (int i = n; i < (2 * n); i++) { - map.put(i, i); - } - - assertEquals(map.capacity(), 2 * n); - assertEquals(map.size(), n); - } - - @Test - public void concurrentInsertions() throws Throwable { - ConcurrentOpenHashMap map = - ConcurrentOpenHashMap.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - String value = "value"; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.put(key, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void concurrentInsertionsAndReads() throws Throwable { - ConcurrentOpenHashMap map = - ConcurrentOpenHashMap.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - String value = "value"; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are uniques - key -= key % (threadIdx + 1); - - map.put(key, value); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void testIteration() { - ConcurrentOpenHashMap map = - ConcurrentOpenHashMap.newBuilder().build(); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0L, "zero"); - - assertEquals(map.keys(), Lists.newArrayList(0L)); - assertEquals(map.values(), Lists.newArrayList("zero")); - - map.remove(0L); - - assertEquals(map.keys(), Collections.emptyList()); - assertEquals(map.values(), Collections.emptyList()); - - map.put(0L, "zero"); - map.put(1L, "one"); - map.put(2L, "two"); - - List keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(0L, 1L, 2L)); - - List values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList("one", "two", "zero")); - - map.put(1L, "uno"); - - keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(0L, 1L, 2L)); - - values = map.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList("two", "uno", "zero")); - - map.clear(); - assertTrue(map.isEmpty()); - } - - @Test - public void testHashConflictWithDeletion() { - final int buckets = 16; - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(buckets) - .concurrencyLevel(1) - .build(); - - // Pick 2 keys that fall into the same bucket - long key1 = 1; - long key2 = 27; - - int bucket1 = ConcurrentOpenHashMap.signSafeMod(ConcurrentOpenHashMap.hash(key1), buckets); - int bucket2 = ConcurrentOpenHashMap.signSafeMod(ConcurrentOpenHashMap.hash(key2), buckets); - assertEquals(bucket1, bucket2); - - assertEquals(map.put(key1, "value-1"), null); - assertEquals(map.put(key2, "value-2"), null); - assertEquals(map.size(), 2); - - assertEquals(map.remove(key1), "value-1"); - assertEquals(map.size(), 1); - - assertEquals(map.put(key1, "value-1-overwrite"), null); - assertEquals(map.size(), 2); - - assertEquals(map.remove(key1), "value-1-overwrite"); - assertEquals(map.size(), 1); - - assertEquals(map.put(key2, "value-2-overwrite"), "value-2"); - assertEquals(map.get(key2), "value-2-overwrite"); - - assertEquals(map.size(), 1); - assertEquals(map.remove(key2), "value-2-overwrite"); - assertTrue(map.isEmpty()); - } - - @Test - public void testPutIfAbsent() { - ConcurrentOpenHashMap map = - ConcurrentOpenHashMap.newBuilder().build(); - assertEquals(map.putIfAbsent(1L, "one"), null); - assertEquals(map.get(1L), "one"); - - assertEquals(map.putIfAbsent(1L, "uno"), "one"); - assertEquals(map.get(1L), "one"); - } - - @Test - public void testComputeIfAbsent() { - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(16) - .concurrencyLevel(1) - .build(); - AtomicInteger counter = new AtomicInteger(); - Function provider = key -> counter.getAndIncrement(); - - assertEquals(map.computeIfAbsent(0, provider).intValue(), 0); - assertEquals(map.get(0).intValue(), 0); - - assertEquals(map.computeIfAbsent(1, provider).intValue(), 1); - assertEquals(map.get(1).intValue(), 1); - - assertEquals(map.computeIfAbsent(1, provider).intValue(), 1); - assertEquals(map.get(1).intValue(), 1); - - assertEquals(map.computeIfAbsent(2, provider).intValue(), 2); - assertEquals(map.get(2).intValue(), 2); - } - - @Test - public void testRemoval() { - ConcurrentOpenHashMap map = - ConcurrentOpenHashMap.newBuilder().build(); - map.put(0, "0"); - map.put(1, "1"); - map.put(3, "3"); - map.put(6, "6"); - map.put(7, "7"); - - List keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(0, 1, 3, 6, 7)); - - int numOfItemsDeleted = map.removeIf(new BiPredicate() { - @Override - public boolean test(Integer k, String v) { - return k < 5; - } - }); - assertEquals(numOfItemsDeleted, 3); - assertEquals(map.size(), keys.size() - numOfItemsDeleted); - keys = map.keys(); - Collections.sort(keys); - assertEquals(keys, Lists.newArrayList(6, 7)); - } - - @Test - public void testEqualsKeys() { - class T { - int value; - - T(int value) { - this.value = value; - } - - @Override - public int hashCode() { - return Integer.hashCode(value); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof T) { - return value == ((T) obj).value; - } - - return false; - } - } - - ConcurrentOpenHashMap map = - ConcurrentOpenHashMap.newBuilder().build(); - - T t1 = new T(1); - T t1B = new T(1); - T t2 = new T(2); - - assertEquals(t1, t1B); - assertFalse(t1.equals(t2)); - assertFalse(t1B.equals(t2)); - - assertNull(map.put(t1, "t1")); - assertEquals(map.get(t1), "t1"); - assertEquals(map.get(t1B), "t1"); - assertNull(map.get(t2)); - - assertEquals(map.remove(t1B), "t1"); - assertNull(map.get(t1)); - assertNull(map.get(t1B)); - } - - static final int Iterations = 1; - static final int ReadIterations = 100; - static final int N = 1_000_000; - - public void benchConcurrentOpenHashMap() throws Exception { - // public static void main(String args[]) { - ConcurrentOpenHashMap map = ConcurrentOpenHashMap.newBuilder() - .expectedItems(N) - .concurrencyLevel(1) - .build(); - - for (long i = 0; i < Iterations; i++) { - for (int j = 0; j < N; j++) { - map.put(i, "value"); - } - - for (long h = 0; h < ReadIterations; h++) { - for (int j = 0; j < N; j++) { - map.get(i); - } - } - - for (long j = 0; j < N; j++) { - map.remove(i); - } - } - } - - public void benchConcurrentHashMap() throws Exception { - ConcurrentHashMap map = new ConcurrentHashMap(N, 0.66f, 1); - - for (long i = 0; i < Iterations; i++) { - for (int j = 0; j < N; j++) { - map.put(i, "value"); - } - - for (long h = 0; h < ReadIterations; h++) { - for (int j = 0; j < N; j++) { - map.get(i); - } - } - - for (int j = 0; j < N; j++) { - map.remove(i); - } - } - } - - void benchHashMap() throws Exception { - HashMap map = new HashMap(N, 0.66f); - - for (long i = 0; i < Iterations; i++) { - for (int j = 0; j < N; j++) { - map.put(i, "value"); - } - - for (long h = 0; h < ReadIterations; h++) { - for (int j = 0; j < N; j++) { - map.get(i); - } - } - - for (int j = 0; j < N; j++) { - map.remove(i); - } - } - } - - public static void main(String[] args) throws Exception { - ConcurrentOpenHashMapTest t = new ConcurrentOpenHashMapTest(); - - long start = System.nanoTime(); - // t.benchHashMap(); - long end = System.nanoTime(); - - System.out.println("HM: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); - - start = System.nanoTime(); - t.benchConcurrentHashMap(); - end = System.nanoTime(); - - System.out.println("CHM: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); - - start = System.nanoTime(); - // t.benchConcurrentOpenHashMap(); - end = System.nanoTime(); - - System.out.println("CLHM: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); - - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashSetTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashSetTest.java deleted file mode 100644 index 8875be2f579..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashSetTest.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util.collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import org.junit.Test; - -/** - * Test the concurrent open HashSet class. - */ -public class ConcurrentOpenHashSetTest { - - @Test - public void testConstructor() { - try { - ConcurrentOpenHashSet.newBuilder() - .expectedItems(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentOpenHashSet.newBuilder() - .expectedItems(14) - .concurrencyLevel(0) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - - try { - ConcurrentOpenHashSet.newBuilder() - .expectedItems(4) - .concurrencyLevel(8) - .build(); - fail("should have thrown exception"); - } catch (IllegalArgumentException e) { - // ok - } - } - - @Test - public void simpleInsertions() { - ConcurrentOpenHashSet set = ConcurrentOpenHashSet.newBuilder() - .expectedItems(16) - .build(); - - assertTrue(set.isEmpty()); - assertTrue(set.add("1")); - assertFalse(set.isEmpty()); - - assertTrue(set.add("2")); - assertTrue(set.add("3")); - - assertEquals(set.size(), 3); - - assertTrue(set.contains("1")); - assertEquals(set.size(), 3); - - assertTrue(set.remove("1")); - assertEquals(set.size(), 2); - assertFalse(set.contains("1")); - assertFalse(set.contains("5")); - assertEquals(set.size(), 2); - - assertTrue(set.add("1")); - assertEquals(set.size(), 3); - assertFalse(set.add("1")); - assertEquals(set.size(), 3); - } - - @Test - public void testClear() { - ConcurrentOpenHashSet map = ConcurrentOpenHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertTrue(map.add("k1")); - assertTrue(map.add("k2")); - assertTrue(map.add("k3")); - - assertTrue(map.capacity() == 8); - map.clear(); - assertTrue(map.capacity() == 4); - } - - @Test - public void testExpandAndShrink() { - ConcurrentOpenHashSet map = ConcurrentOpenHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - assertTrue(map.capacity() == 4); - - assertTrue(map.add("k1")); - assertTrue(map.add("k2")); - assertTrue(map.add("k3")); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove("k1")); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove("k2")); - // shrink hashmap - assertTrue(map.capacity() == 4); - - // expand hashmap - assertTrue(map.add("k4")); - assertTrue(map.add("k5")); - assertTrue(map.capacity() == 8); - - //verify that the map does not keep shrinking at every remove() operation - assertTrue(map.add("k6")); - assertTrue(map.remove("k6")); - assertTrue(map.capacity() == 8); - } - - @Test - public void testExpandShrinkAndClear() { - ConcurrentOpenHashSet map = ConcurrentOpenHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .autoShrink(true) - .mapIdleFactor(0.25f) - .build(); - final long initCapacity = map.capacity(); - assertTrue(map.capacity() == 4); - - assertTrue(map.add("k1")); - assertTrue(map.add("k2")); - assertTrue(map.add("k3")); - - // expand hashmap - assertTrue(map.capacity() == 8); - - assertTrue(map.remove("k1")); - // not shrink - assertTrue(map.capacity() == 8); - assertTrue(map.remove("k2")); - // shrink hashmap - assertTrue(map.capacity() == 4); - - assertTrue(map.remove("k3")); - // Will not shrink the hashmap again because shrink capacity is less than initCapacity - // current capacity is equal than the initial capacity - assertTrue(map.capacity() == initCapacity); - map.clear(); - // after clear, because current capacity is equal than the initial capacity, so not shrinkToInitCapacity - assertTrue(map.capacity() == initCapacity); - } - - @Test - public void testReduceUnnecessaryExpansions(){ - ConcurrentOpenHashSet set = - ConcurrentOpenHashSet.newBuilder() - .expectedItems(2) - .concurrencyLevel(1) - .build(); - - assertTrue(set.add("1")); - assertTrue(set.add("2")); - assertTrue(set.add("3")); - assertTrue(set.add("4")); - - assertTrue(set.remove("1")); - assertTrue(set.remove("2")); - assertTrue(set.remove("3")); - assertTrue(set.remove("4")); - assertEquals(0, set.getUsedBucketCount()); - } - - @Test - public void testRemove() { - ConcurrentOpenHashSet set = - ConcurrentOpenHashSet.newBuilder().build(); - - assertTrue(set.isEmpty()); - assertTrue(set.add("1")); - assertFalse(set.isEmpty()); - - assertFalse(set.remove("0")); - assertFalse(set.isEmpty()); - assertTrue(set.remove("1")); - assertTrue(set.isEmpty()); - } - - @Test - public void testRehashing() { - int n = 16; - ConcurrentOpenHashSet set = ConcurrentOpenHashSet.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(set.capacity(), n); - assertEquals(set.size(), 0); - - for (int i = 0; i < n; i++) { - set.add(i); - } - - assertEquals(set.capacity(), 2 * n); - assertEquals(set.size(), n); - } - - @Test - public void testRehashingWithDeletes() { - int n = 16; - ConcurrentOpenHashSet set = ConcurrentOpenHashSet.newBuilder() - .expectedItems(n / 2) - .concurrencyLevel(1) - .build(); - assertEquals(set.capacity(), n); - assertEquals(set.size(), 0); - - for (int i = 0; i < n / 2; i++) { - set.add(i); - } - - for (int i = 0; i < n / 2; i++) { - set.remove(i); - } - - for (int i = n; i < (2 * n); i++) { - set.add(i); - } - - assertEquals(set.capacity(), 2 * n); - assertEquals(set.size(), n); - } - - @Test - public void concurrentInsertions() throws Throwable { - ConcurrentOpenHashSet set = - ConcurrentOpenHashSet.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are unique - key -= key % (threadIdx + 1); - - set.add(key); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(set.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void concurrentInsertionsAndReads() throws Throwable { - ConcurrentOpenHashSet map = - ConcurrentOpenHashSet.newBuilder().build(); - ExecutorService executor = Executors.newCachedThreadPool(); - - final int nThreads = 16; - final int n = 100_000; - - List> futures = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - final int threadIdx = i; - - futures.add(executor.submit(() -> { - Random random = new Random(); - - for (int j = 0; j < n; j++) { - long key = random.nextLong(); - // Ensure keys are unique - key -= key % (threadIdx + 1); - - map.add(key); - } - })); - } - - for (Future future : futures) { - future.get(); - } - - assertEquals(map.size(), n * nThreads); - - executor.shutdown(); - } - - @Test - public void testIteration() { - ConcurrentOpenHashSet set = - ConcurrentOpenHashSet.newBuilder().build(); - - assertEquals(set.values(), Collections.emptyList()); - - set.add(0L); - - assertEquals(set.values(), Lists.newArrayList(0L)); - - set.remove(0L); - - assertEquals(set.values(), Collections.emptyList()); - - set.add(0L); - set.add(1L); - set.add(2L); - - List values = set.values(); - Collections.sort(values); - assertEquals(values, Lists.newArrayList(0L, 1L, 2L)); - - set.clear(); - assertTrue(set.isEmpty()); - } - - @Test - public void testHashConflictWithDeletion() { - final int buckets = 16; - ConcurrentOpenHashSet set = ConcurrentOpenHashSet.newBuilder() - .expectedItems(buckets) - .concurrencyLevel(1) - .build(); - - // Pick 2 keys that fall into the same bucket - long key1 = 1; - long key2 = 27; - - int bucket1 = ConcurrentOpenHashSet.signSafeMod(ConcurrentOpenHashSet.hash(key1), buckets); - int bucket2 = ConcurrentOpenHashSet.signSafeMod(ConcurrentOpenHashSet.hash(key2), buckets); - assertEquals(bucket1, bucket2); - - assertTrue(set.add(key1)); - assertTrue(set.add(key2)); - assertEquals(set.size(), 2); - - assertTrue(set.remove(key1)); - assertEquals(set.size(), 1); - - assertTrue(set.add(key1)); - assertEquals(set.size(), 2); - - assertTrue(set.remove(key1)); - assertEquals(set.size(), 1); - - assertFalse(set.add(key2)); - assertTrue(set.contains(key2)); - - assertEquals(set.size(), 1); - assertTrue(set.remove(key2)); - assertTrue(set.isEmpty()); - } - - @Test - public void testEqualsObjects() { - class T { - int value; - - T(int value) { - this.value = value; - } - - @Override - public int hashCode() { - return Integer.hashCode(value); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof T) { - return value == ((T) obj).value; - } - - return false; - } - } - - ConcurrentOpenHashSet set = - ConcurrentOpenHashSet.newBuilder().build(); - - T t1 = new T(1); - T t1B = new T(1); - T t2 = new T(2); - - assertEquals(t1, t1B); - assertFalse(t1.equals(t2)); - assertFalse(t1B.equals(t2)); - - set.add(t1); - assertTrue(set.contains(t1)); - assertTrue(set.contains(t1B)); - assertFalse(set.contains(t2)); - - assertTrue(set.remove(t1B)); - assertFalse(set.contains(t1)); - assertFalse(set.contains(t1B)); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/SynchronizedHashMultiMapTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/SynchronizedHashMultiMapTest.java deleted file mode 100644 index c58093848b6..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/SynchronizedHashMultiMapTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.util.collections; - -import java.util.Optional; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test for SynchronizedHashMultiMap. - */ -public class SynchronizedHashMultiMapTest { - @Test - public void testGetAnyKey() { - SynchronizedHashMultiMap map = new SynchronizedHashMultiMap<>(); - Assert.assertFalse(map.getAnyKey().isPresent()); - - map.put(1, 2); - Assert.assertEquals(map.getAnyKey().get(), Integer.valueOf(1)); - - map.put(1, 3); - Assert.assertEquals(map.getAnyKey().get(), Integer.valueOf(1)); - - map.put(2, 4); - int res = map.getAnyKey().get(); - Assert.assertTrue(res == 1 || res == 2); - - map.removeIf((k, v) -> k == 1); - Assert.assertEquals(map.getAnyKey().get(), Integer.valueOf(2)); - } - - @Test - public void testRemoveAny() { - SynchronizedHashMultiMap map = new SynchronizedHashMultiMap<>(); - Assert.assertFalse(map.removeAny(1).isPresent()); - - map.put(1, 2); - map.put(1, 3); - map.put(2, 4); - map.put(2, 4); - - Optional v = map.removeAny(1); - int firstVal = v.get(); - Assert.assertTrue(firstVal == 2 || firstVal == 3); - - v = map.removeAny(1); - int secondVal = v.get(); - Assert.assertTrue(secondVal == 2 || secondVal == 3); - Assert.assertNotEquals(secondVal, firstVal); - - v = map.removeAny(2); - Assert.assertTrue(v.isPresent()); - Assert.assertEquals(v.get(), Integer.valueOf(4)); - - Assert.assertFalse(map.removeAny(1).isPresent()); - Assert.assertFalse(map.removeAny(2).isPresent()); - Assert.assertFalse(map.removeAny(3).isPresent()); - } - - @Test - public void testRemoveIf() { - SynchronizedHashMultiMap map = new SynchronizedHashMultiMap<>(); - Assert.assertEquals(map.removeIf((k, v) -> true), 0); - - map.put(1, 2); - map.put(1, 3); - map.put(2, 4); - map.put(2, 4); - - Assert.assertEquals(map.removeIf((k, v) -> v == 4), 1); - Assert.assertEquals(map.removeIf((k, v) -> k == 1), 2); - - map.put(1, 2); - map.put(1, 3); - map.put(2, 4); - - Assert.assertEquals(map.removeIf((k, v) -> false), 0); - Assert.assertEquals(map.removeIf((k, v) -> true), 3); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/verifier/BookkeeperVerifierTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/verifier/BookkeeperVerifierTest.java deleted file mode 100644 index 6681c018b81..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/verifier/BookkeeperVerifierTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ - -package org.apache.bookkeeper.verifier; - -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.junit.Test; - -/** - * Test for BookKeeperVerifier. - */ -public class BookkeeperVerifierTest extends BookKeeperClusterTestCase { - public BookkeeperVerifierTest() { - super(3); - } - - /** - * Simple test to verify that the verifier works against a local cluster. - */ - @Test(timeout = 30000) - public void testBasic() throws Exception { - DirectBookkeeperDriver driver = new DirectBookkeeperDriver(bkc); - BookkeeperVerifier verifier = new BookkeeperVerifier( - driver, - 3, - 3, - 2, - 10, - 5, - 16, - 4, - 2, - 2, - 32, - 16 << 10, - 4 << 10, - 4, - 0.5 - ); - verifier.run(); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/versioning/TestLongVersion.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/versioning/TestLongVersion.java deleted file mode 100644 index 5e1e7e23542..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/versioning/TestLongVersion.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.versioning; - -import org.apache.bookkeeper.versioning.Version.Occurred; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test long version. - */ -public class TestLongVersion { - - @Test - public void testNullIntVersion() { - LongVersion longVersion = new LongVersion(99); - try { - longVersion.compare(null); - Assert.fail("Should fail comparing with null version."); - } catch (NullPointerException npe) { - } - } - - @Test - public void testInvalidVersion() { - LongVersion longVersion = new LongVersion(99); - try { - longVersion.compare(v -> Occurred.AFTER); - Assert.fail("Should not reach here!"); - } catch (IllegalArgumentException iae) { - } - } - - @Test - public void testCompare() { - LongVersion iv = new LongVersion(99); - Assert.assertEquals(Occurred.AFTER, iv.compare(new LongVersion(98))); - Assert.assertEquals(Occurred.BEFORE, iv.compare(new LongVersion(100))); - Assert.assertEquals(Occurred.CONCURRENTLY, iv.compare(new LongVersion(99))); - Assert.assertEquals(Occurred.CONCURRENTLY, iv.compare(Version.ANY)); - Assert.assertEquals(Occurred.AFTER, iv.compare(Version.NEW)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/MockZooKeeperTestCase.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/MockZooKeeperTestCase.java deleted file mode 100644 index 73f6762f963..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/MockZooKeeperTestCase.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.zookeeper; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; - -import com.google.common.collect.Maps; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.api.BKException.Code; -import org.apache.bookkeeper.common.testing.executors.MockExecutorController; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.zookeeper.AsyncCallback.Children2Callback; -import org.apache.zookeeper.AsyncCallback.DataCallback; -import org.apache.zookeeper.AsyncCallback.StatCallback; -import org.apache.zookeeper.AsyncCallback.StringCallback; -import org.apache.zookeeper.AsyncCallback.VoidCallback; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.data.Stat; -import org.mockito.MockedStatic; - -/** - * A test base that provides mocked zookeeper. - */ -public abstract class MockZooKeeperTestCase { - - protected final ConcurrentMap> watchers = Maps.newConcurrentMap(); - protected ZooKeeper mockZk; - protected ScheduledExecutorService zkCallbackExecutor; - protected MockExecutorController zkCallbackController; - private MockedStatic zkUtilsMockedStatic; - - protected void setup() throws Exception { - this.mockZk = mock(ZooKeeper.class); - - this.zkUtilsMockedStatic = mockStatic(ZkUtils.class); - - this.zkCallbackExecutor = mock(ScheduledExecutorService.class); - this.zkCallbackController = new MockExecutorController() - .controlExecute(zkCallbackExecutor) - .controlSubmit(zkCallbackExecutor) - .controlSchedule(zkCallbackExecutor) - .controlScheduleAtFixedRate(zkCallbackExecutor, 10); - } - - protected void teardown() throws Exception { - zkUtilsMockedStatic.close(); - } - - private void addWatcher(String path, Watcher watcher) { - if (null == watcher) { - return; - } - Set watcherSet = watchers.get(path); - if (null == watcherSet) { - watcherSet = new HashSet<>(); - watchers.put(path, watcherSet); - } - watcherSet.add(watcher); - } - - private void removeWatcher(String path, Watcher watcher) { - if (watcher == null) { - return; - } - Set watcherSet = watchers.get(path); - if (null == watcherSet) { - return; - } - watcherSet.remove(watcher); - if (watcherSet.isEmpty()) { - watchers.remove(path); - } - } - - protected void mockZkUtilsAsyncCreateFullPathOptimistic( - String expectedLedgerPath, - CreateMode expectedCreateMode, - int retCode, - String retCreatedZnodeName - ) throws Exception { - zkUtilsMockedStatic.when(() -> ZkUtils.asyncCreateFullPathOptimistic( - eq(mockZk), - eq(expectedLedgerPath), - any(byte[].class), - anyList(), - eq(expectedCreateMode), - any(StringCallback.class), - any())).thenAnswer(invocationOnMock -> { - String path = invocationOnMock.getArgument(1); - StringCallback callback = invocationOnMock.getArgument(5); - Object ctx = invocationOnMock.getArgument(6); - - callback.processResult( - retCode, path, ctx, retCreatedZnodeName); - return null; - }); - } - - protected void mockZkDelete( - String expectedLedgerPath, - int expectedVersion, - int retCode - ) throws Exception { - - doAnswer(invocationOnMock -> { - String path = invocationOnMock.getArgument(0); - VoidCallback callback = invocationOnMock.getArgument(2); - Object ctx = invocationOnMock.getArgument(3); - - callback.processResult( - retCode, path, ctx - ); - - return null; - }).when(mockZk).delete( - eq(expectedLedgerPath), - eq(expectedVersion), - any(VoidCallback.class), - any()); - - } - - protected void mockZkUtilsAsyncDeleteFullPathOptimistic( - String expectedLedgerPath, - int expectedZnodeVersion, - int retCode - ) throws Exception { - zkUtilsMockedStatic.when(() -> ZkUtils.asyncDeleteFullPathOptimistic( - eq(mockZk), - eq(expectedLedgerPath), - eq(expectedZnodeVersion), - any(VoidCallback.class), - eq(expectedLedgerPath))).thenAnswer(invocationOnMock -> { - String path = invocationOnMock.getArgument(1); - VoidCallback callback = invocationOnMock.getArgument(3); - - callback.processResult( - retCode, path, null); - return null; - }); - } - - protected void mockZkGetData( - String expectedLedgerPath, - boolean expectedWatcher, - int retCode, - byte[] retData, - Stat retStat - ) throws Exception { - - doAnswer(invocationOnMock -> { - String path = invocationOnMock.getArgument(0); - Watcher watcher = invocationOnMock.getArgument(1); - DataCallback callback = invocationOnMock.getArgument(2); - Object ctx = invocationOnMock.getArgument(3); - - if (Code.OK == retCode) { - addWatcher(path, watcher); - } - - callback.processResult( - retCode, path, ctx, retData, retStat - ); - - return null; - }).when(mockZk).getData( - eq(expectedLedgerPath), - expectedWatcher ? any(Watcher.class) : eq(null), - any(DataCallback.class), - any()); - } - - protected void mockZkRemoveWatcher () throws Exception { - doAnswer(invocationOnMock -> { - String path = invocationOnMock.getArgument(0); - Watcher watcher = invocationOnMock.getArgument(1); - VoidCallback callback = invocationOnMock.getArgument(4); - removeWatcher(path, watcher); - - callback.processResult(KeeperException.Code.OK.intValue(), path, null); - return null; - }).when(mockZk).removeWatches( - any(String.class), - any(Watcher.class), - any(Watcher.WatcherType.class), - any(Boolean.class), - any(VoidCallback.class), - any()); - } - - protected void mockZkSetData( - String expectedLedgerPath, - byte[] expectedBytes, - int expectedVersion, - int retCode, - Stat retStat - ) throws Exception { - - doAnswer(invocationOnMock -> { - String path = invocationOnMock.getArgument(0); - StatCallback callback = invocationOnMock.getArgument(3); - Object ctx = invocationOnMock.getArgument(4); - - callback.processResult( - retCode, path, ctx, retStat - ); - - return null; - }).when(mockZk).setData( - eq(expectedLedgerPath), - eq(expectedBytes), - eq(expectedVersion), - any(StatCallback.class), - any()); - - } - - protected boolean notifyWatchedEvent(EventType eventType, - KeeperState keeperState, - String path) { - Set watcherSet = watchers.remove(path); - if (null == watcherSet) { - return false; - } - WatchedEvent event = new WatchedEvent( - eventType, keeperState, path); - for (Watcher watcher : watcherSet) { - watcher.process(event); - } - return true; - } - - protected void mockGetChildren(String expectedPath, - boolean expectedWatcher, - int retCode, - List retChildren, - Stat retStat) { - mockGetChildren( - expectedPath, expectedWatcher, retCode, retChildren, retStat, 0); - } - - protected void mockGetChildren(String expectedPath, - boolean expectedWatcher, - int retCode, - List retChildren, - Stat retStat, - long delayMs) { - doAnswer(invocationOnMock -> { - String p = invocationOnMock.getArgument(0); - Watcher w = invocationOnMock.getArgument(1); - Children2Callback callback = invocationOnMock.getArgument(2); - Object ctx = invocationOnMock.getArgument(3); - - if (Code.OK == retCode) { - addWatcher(p, w); - } - - this.zkCallbackExecutor.schedule(() -> callback.processResult( - retCode, - p, - ctx, - retChildren, - retStat - ), delayMs, TimeUnit.MILLISECONDS); - return null; - - }).when(mockZk).getChildren( - eq(expectedPath), - expectedWatcher ? any(Watcher.class) : eq(null), - any(Children2Callback.class), - any()); - } - -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestRetryPolicy.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestRetryPolicy.java deleted file mode 100644 index 030a7154d99..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestRetryPolicy.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.zookeeper; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Test the retry policy. - */ -public class TestRetryPolicy { - - private static void assertTimeRange(long waitTime, long minTime, long maxTime) { - assertTrue(waitTime >= minTime); - assertTrue(waitTime <= maxTime); - } - - @Test - public void testExponentialBackoffRetryPolicy() throws Exception { - RetryPolicy policy = new ExponentialBackoffRetryPolicy(1000, Integer.MAX_VALUE); - assertTimeRange(policy.nextRetryWaitTime(30, 2000), 1000L, (long) (1000 * Math.pow(2, 31))); - assertTimeRange(policy.nextRetryWaitTime(31, 2000), 1000L, (long) (1000 * Math.pow(2, 32))); - assertTimeRange(policy.nextRetryWaitTime(32, 2000), 1000L, (long) (1000 * Math.pow(2, 33))); - assertTimeRange(policy.nextRetryWaitTime(127, 2000), 1000L, 1000L); - assertTimeRange(policy.nextRetryWaitTime(128, 2000), 1000L, 2000L); - assertTimeRange(policy.nextRetryWaitTime(129, 2000), 1000L, 4000L); - } - - @Test - public void testBoundExponentialBackoffRetryPolicy() throws Exception { - RetryPolicy policy = new BoundExponentialBackoffRetryPolicy(1000, 2000, Integer.MAX_VALUE); - assertTimeRange(policy.nextRetryWaitTime(30, 2000), 1000L, 2000L); - assertTimeRange(policy.nextRetryWaitTime(31, 2000), 1000L, 2000L); - assertTimeRange(policy.nextRetryWaitTime(32, 2000), 1000L, 2000L); - assertTimeRange(policy.nextRetryWaitTime(127, 2000), 1000L, 1000L); - assertTimeRange(policy.nextRetryWaitTime(128, 2000), 1000L, 2000L); - assertTimeRange(policy.nextRetryWaitTime(129, 2000), 1000L, 2000L); - } - - @Test - public void testExponentialBackoffWithDeadlineRetryPolicy() throws Exception { - RetryPolicy policy = new ExponentialBackOffWithDeadlinePolicy(100, 55 * 1000, 20); - - // Retries are allowed as long as we don't exceed the limits of retry count and deadline - assertTrue(policy.allowRetry(1, 5 * 1000)); - assertTrue(policy.allowRetry(4, 20 * 1000)); - assertTrue(policy.allowRetry(10, 50 * 1000)); - - assertFalse(policy.allowRetry(0, 60 * 1000)); - assertFalse(policy.allowRetry(22, 20 * 1000)); - assertFalse(policy.allowRetry(22, 60 * 1000)); - - // Verify that the wait times are in the range and with the excepted jitter, until deadline is exceeded - assertTimeRange(policy.nextRetryWaitTime(0, 0), 0, 0); - assertTimeRange(policy.nextRetryWaitTime(1, 0), 100, 110); - assertTimeRange(policy.nextRetryWaitTime(1, 53 * 1000), 100, 110); - assertTimeRange(policy.nextRetryWaitTime(2, 0), 200, 220); - assertTimeRange(policy.nextRetryWaitTime(3, 0), 300, 330); - assertTimeRange(policy.nextRetryWaitTime(3, 53 * 1000), 300, 330); - assertTimeRange(policy.nextRetryWaitTime(4, 0), 500, 550); - assertTimeRange(policy.nextRetryWaitTime(5, 0), 500, 550); - - // Verify that the final attempt is triggered at deadline. - assertEquals(2000, policy.nextRetryWaitTime(10, 53 * 1000)); - assertEquals(4000, policy.nextRetryWaitTime(15, 51 * 1000)); - } -} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientBoundExpBackoffRP.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientBoundExpBackoffRP.java deleted file mode 100644 index ddf046df440..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientBoundExpBackoffRP.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.zookeeper; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import org.apache.bookkeeper.test.ZooKeeperCluster; -import org.apache.bookkeeper.test.ZooKeeperClusterUtil; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.zookeeper.KeeperException; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -/** - * Test zk client resiliency with BoundExponentialBackoffRetryPolicy. - */ -@RunWith(Parameterized.class) -public class TestZKClientBoundExpBackoffRP extends TestZooKeeperClient { - - public TestZKClientBoundExpBackoffRP(Class zooKeeperUtilClass, - Class retryPolicyClass) - throws IOException, KeeperException, InterruptedException { - super(zooKeeperUtilClass, retryPolicyClass); - } - - @Parameterized.Parameters - public static Collection zooKeeperUtilClass() { - return Arrays.asList(new Object[][] { { ZooKeeperUtil.class, BoundExponentialBackoffRetryPolicy.class }, - { ZooKeeperClusterUtil.class, BoundExponentialBackoffRetryPolicy.class } }); - } - -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientExpBackoffWithDeadlineRP.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientExpBackoffWithDeadlineRP.java deleted file mode 100644 index 73bd3909e3c..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientExpBackoffWithDeadlineRP.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.zookeeper; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import org.apache.bookkeeper.test.ZooKeeperCluster; -import org.apache.bookkeeper.test.ZooKeeperClusterUtil; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.zookeeper.KeeperException; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -/** - * Test zk client resiliency with ExponentialBackOffWithDeadlinePolicy. - */ -@RunWith(Parameterized.class) -public class TestZKClientExpBackoffWithDeadlineRP extends TestZooKeeperClient { - - public TestZKClientExpBackoffWithDeadlineRP(Class zooKeeperUtilClass, - Class retryPolicyClass) - throws IOException, KeeperException, InterruptedException { - super(zooKeeperUtilClass, retryPolicyClass); - } - - @Parameterized.Parameters - public static Collection zooKeeperUtilClass() { - return Arrays.asList(new Object[][] { { ZooKeeperUtil.class, ExponentialBackOffWithDeadlinePolicy.class }, - { ZooKeeperClusterUtil.class, ExponentialBackOffWithDeadlinePolicy.class } }); - } - -} \ No newline at end of file diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZooKeeperClient.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZooKeeperClient.java deleted file mode 100644 index 3c1bd65a64b..00000000000 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZooKeeperClient.java +++ /dev/null @@ -1,898 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.zookeeper; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import junit.framework.TestCase; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.ZooKeeperCluster; -import org.apache.bookkeeper.test.ZooKeeperClusterUtil; -import org.apache.bookkeeper.test.ZooKeeperUtil; -import org.apache.zookeeper.AsyncCallback; -import org.apache.zookeeper.AsyncCallback.ACLCallback; -import org.apache.zookeeper.AsyncCallback.Children2Callback; -import org.apache.zookeeper.AsyncCallback.DataCallback; -import org.apache.zookeeper.AsyncCallback.StatCallback; -import org.apache.zookeeper.AsyncCallback.StringCallback; -import org.apache.zookeeper.AsyncCallback.VoidCallback; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.data.ACL; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test the wrapper of {@link org.apache.zookeeper.ZooKeeper} client. - */ -@RunWith(Parameterized.class) -public abstract class TestZooKeeperClient extends TestCase { - - static { - ZooKeeperClusterUtil.enableZookeeperTestEnvVariables(); - } - - private static final Logger logger = LoggerFactory.getLogger(TestZooKeeperClient.class); - - // ZooKeeper related variables - protected ZooKeeperCluster zkUtil; - private RetryPolicy retryPolicy; - - public TestZooKeeperClient(Class zooKeeperUtilClass, - Class retryPolicyClass) - throws IOException, KeeperException, InterruptedException { - if (zooKeeperUtilClass.equals(ZooKeeperUtil.class)) { - zkUtil = new ZooKeeperUtil(); - } else { - zkUtil = new ZooKeeperClusterUtil(3); - } - if (retryPolicyClass.equals(BoundExponentialBackoffRetryPolicy.class)) { - retryPolicy = new BoundExponentialBackoffRetryPolicy(2000, - 2000, Integer.MAX_VALUE); - } else { - retryPolicy = new ExponentialBackOffWithDeadlinePolicy(100, - 20 * 1000, Integer.MAX_VALUE); - } - } - - @Before - @Override - public void setUp() throws Exception { - logger.info("Setting up test {}.", getName()); - zkUtil.startCluster(); - } - - @After - @Override - public void tearDown() throws Exception { - zkUtil.killCluster(); - logger.info("Teared down test {}.", getName()); - } - - private void expireZooKeeperSession(ZooKeeper zk, int timeout) - throws IOException, InterruptedException, KeeperException { - final CountDownLatch latch = new CountDownLatch(1); - ZooKeeper newZk = new ZooKeeper(zkUtil.getZooKeeperConnectString(), timeout, - new Watcher() { - - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.None && event.getState() == KeeperState.SyncConnected) { - latch.countDown(); - } - } - - }, zk.getSessionId(), zk.getSessionPasswd()); - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - throw KeeperException.create(KeeperException.Code.CONNECTIONLOSS); - } - newZk.close(); - } - - /** - * Shutdown Zk Server when client received an expire event. - * So the client issue recreation client task but it would not succeed - * until we start the zookeeper server again. - */ - class ShutdownZkServerClient extends ZooKeeperClient { - - ShutdownZkServerClient(String connectString, int sessionTimeoutMs, - ZooKeeperWatcherBase watcher, RetryPolicy operationRetryPolicy) - throws IOException { - super(connectString, sessionTimeoutMs, watcher, - new BoundExponentialBackoffRetryPolicy(sessionTimeoutMs, sessionTimeoutMs, Integer.MAX_VALUE), - operationRetryPolicy, - NullStatsLogger.INSTANCE, 1, 0, false); - } - - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.None && event.getState() == KeeperState.Expired) { - try { - zkUtil.stopCluster(); - } catch (Exception e) { - logger.error("Failed to stop zookeeper server : ", e); - } - } - super.process(event); - } - - } - - @Test - public void testReconnectAfterExipred() throws Exception { - final CountDownLatch expireLatch = new CountDownLatch(1); - Watcher testWatcher = new Watcher() { - - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.None && event.getState() == KeeperState.Expired) { - expireLatch.countDown(); - } - } - - }; - final int timeout = 2000; - ZooKeeperWatcherBase watcherManager = - new ZooKeeperWatcherBase(timeout).addChildWatcher(testWatcher); - List watchers = new ArrayList(1); - watchers.add(testWatcher); - ZooKeeperClient client = new ShutdownZkServerClient( - zkUtil.getZooKeeperConnectString(), timeout, watcherManager, - ((retryPolicy instanceof BoundExponentialBackoffRetryPolicy) - ? new BoundExponentialBackoffRetryPolicy(timeout, timeout, 0) : - new ExponentialBackOffWithDeadlinePolicy(100, 20 * 1000, 0))); - client.waitForConnection(); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", - client.getState().isConnected()); - logger.info("Expire zookeeper client"); - expireZooKeeperSession(client, timeout); - - // wait until session expire - Assert.assertTrue("Client registered watcher should receive expire event.", - expireLatch.await(2 * timeout, TimeUnit.MILLISECONDS)); - - Assert.assertFalse("Client doesn't receive expire event from ZooKeeper.", - client.getState().isConnected()); - - try { - client.exists("/tmp", false); - Assert.fail("Should fail due to connection loss."); - } catch (KeeperException.ConnectionLossException cle) { - // expected - } catch (KeeperException.SessionExpiredException cle) { - // expected - } - - zkUtil.restartCluster(); - - // wait for a reconnect cycle - Thread.sleep(2 * timeout); - Assert.assertTrue("Client failed to connect zookeeper even it was back.", - client.getState().isConnected()); - try { - client.exists("/tmp", false); - } catch (KeeperException.ConnectionLossException cle) { - Assert.fail("Should not throw ConnectionLossException"); - } catch (KeeperException.SessionExpiredException cle) { - Assert.fail("Should not throw SessionExpiredException"); - } - } - - @Test - public void testRetrySyncOperations() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient( - zkUtil.getZooKeeperConnectString(), timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", - client.getState().isConnected()); - - String path = "/a"; - byte[] data = "test".getBytes(); - - expireZooKeeperSession(client, timeout); - logger.info("Create znode " + path); - client.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - logger.info("Created znode " + path); - - expireZooKeeperSession(client, timeout); - logger.info("Exists znode " + path); - Stat stat = client.exists(path, false); - Assert.assertNotNull("znode doesn't existed", stat); - - expireZooKeeperSession(client, timeout); - logger.info("Get data from znode " + path); - Stat newStat = new Stat(); - client.getData(path, false, newStat); - Assert.assertEquals(stat, newStat); - - expireZooKeeperSession(client, timeout); - logger.info("Create children under znode " + path); - client.create(path + "/children", data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - expireZooKeeperSession(client, timeout); - logger.info("Create children under znode " + path); - client.create(path + "/children2", data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - expireZooKeeperSession(client, timeout); - List children = client.getChildren(path, false, newStat); - Assert.assertEquals(2, children.size()); - Assert.assertTrue(children.contains("children")); - Assert.assertTrue(children.contains("children2")); - logger.info("Get children under znode " + path); - - expireZooKeeperSession(client, timeout); - client.delete(path + "/children", -1); - logger.info("Delete children from znode " + path); - } - - @Test - public void testSyncAfterSessionExpiry() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), - timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", client.getState().isConnected()); - - String path = "/testSyncAfterSessionExpiry"; - byte[] data = "test".getBytes(); - - // create a node - logger.info("Create znode " + path); - List setACLList = new ArrayList(); - setACLList.addAll(Ids.OPEN_ACL_UNSAFE); - client.create(path, data, setACLList, CreateMode.PERSISTENT); - - // expire the ZKClient session - expireZooKeeperSession(client, timeout); - - // the current Client connection should be in connected state even after the session expiry - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", client.getState().isConnected()); - - // even after the previous session expiry client should be able to sync - CountDownLatch latch = new CountDownLatch(1); - final int[] rcArray = { -1 }; - client.sync(path, new VoidCallback() { - @Override - public void processResult(int rc, String path, Object ctx) { - CountDownLatch cdLatch = (CountDownLatch) ctx; - rcArray[0] = rc; - cdLatch.countDown(); - } - }, latch); - Assert.assertTrue("client.sync operation should have completed successfully", - latch.await(6000, TimeUnit.MILLISECONDS)); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Sync failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - - // delete the node - client.delete(path, -1); - } - - @Test - public void testACLSetAndGet() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), - timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", client.getState().isConnected()); - - String path = "/testACLSetAndGet"; - byte[] data = "test".getBytes(); - - // create a node and call getACL to verify the received ACL - logger.info("Create znode " + path); - List setACLList = new ArrayList(); - setACLList.addAll(Ids.OPEN_ACL_UNSAFE); - client.create(path, data, setACLList, CreateMode.PERSISTENT); - Stat status = new Stat(); - List receivedACLList = client.getACL(path, status); - Assert.assertEquals("Test1 - ACLs are expected to match", setACLList, receivedACLList); - - // update node's ACL and call getACL to verify the received ACL - setACLList.clear(); - setACLList.addAll(Ids.OPEN_ACL_UNSAFE); - setACLList.addAll(Ids.READ_ACL_UNSAFE); - status = client.setACL(path, setACLList, status.getAversion()); - receivedACLList = client.getACL(path, status); - Assert.assertEquals("Test2 - ACLs are expected to match", setACLList, receivedACLList); - - // update node's ACL by calling async setACL and call async getACL to verify the received ACL - setACLList.clear(); - setACLList.addAll(Ids.OPEN_ACL_UNSAFE); - CountDownLatch latch = new CountDownLatch(1); - final Stat[] statArray = { null }; - final int[] rcArray = { -1 }; - client.setACL(path, setACLList, status.getAversion(), new StatCallback() { - @Override - public void processResult(int rc, String path, Object ctx, Stat stat) { - CountDownLatch cdLatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statArray[0] = stat; - cdLatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test3 - SetACL call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - status = statArray[0]; - latch = new CountDownLatch(1); - rcArray[0] = 0; - statArray[0] = null; - final List> aclListArray = new ArrayList>(1); - client.getACL(path, status, new ACLCallback() { - @Override - public void processResult(int rc, String path, Object ctx, List acl, Stat stat) { - CountDownLatch cdLatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statArray[0] = stat; - aclListArray.add(acl); - cdLatch.countDown(); - } - - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test4 - GetACL call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - status = statArray[0]; - receivedACLList = aclListArray.get(0); - Assert.assertEquals("Test5 - ACLs are expected to match", setACLList, receivedACLList); - - // delete the node - client.delete(path, status.getVersion()); - } - - @Test - public void testACLSetAndGetAfterSessionExpiry() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), - timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", client.getState().isConnected()); - - String path = "/testACLSetAndGetAfterSessionExpiry"; - byte[] data = "test".getBytes(); - - // create a node - logger.info("Create znode " + path); - List setACLList = new ArrayList(); - setACLList.addAll(Ids.OPEN_ACL_UNSAFE); - client.create(path, data, setACLList, CreateMode.PERSISTENT); - - // expire the ZKClient session - expireZooKeeperSession(client, timeout); - - // call getACL and verify if it returns the previously set ACL - Stat status = new Stat(); - List receivedACLList = client.getACL(path, status); - Assert.assertEquals("Test1 - ACLs are expected to match", setACLList, receivedACLList); - - // update ACL of that node - setACLList.clear(); - setACLList.addAll(Ids.OPEN_ACL_UNSAFE); - setACLList.addAll(Ids.READ_ACL_UNSAFE); - status = client.setACL(path, setACLList, status.getAversion()); - - // expire the ZKClient session - expireZooKeeperSession(client, timeout); - - // call getACL and verify if it returns the previously set ACL - receivedACLList = client.getACL(path, status); - Assert.assertEquals("Test2 - ACLs are expected to match", setACLList, receivedACLList); - - // update the ACL of node by calling async setACL - setACLList.clear(); - setACLList.addAll(Ids.OPEN_ACL_UNSAFE); - CountDownLatch latch = new CountDownLatch(1); - final Stat[] statArray = { null }; - final int[] rcArray = { -1 }; - client.setACL(path, setACLList, status.getAversion(), new StatCallback() { - @Override - public void processResult(int rc, String path, Object ctx, Stat stat) { - CountDownLatch cdLatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statArray[0] = stat; - cdLatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test3 - SetACL call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - status = statArray[0]; - - // expire the ZKClient session - expireZooKeeperSession(client, timeout); - - // call async getACL and verify if it returns the previously set ACL - latch = new CountDownLatch(1); - rcArray[0] = 0; - statArray[0] = null; - final List> aclListArray = new ArrayList>(1); - client.getACL(path, status, new ACLCallback() { - @Override - public void processResult(int rc, String path, Object ctx, List acl, Stat stat) { - CountDownLatch cdLatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statArray[0] = stat; - aclListArray.add(acl); - cdLatch.countDown(); - } - - }, latch); - Assert.assertTrue("getACL operation should have completed successfully", - latch.await(6000, TimeUnit.MILLISECONDS)); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test4 - GetACL call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - status = statArray[0]; - receivedACLList = aclListArray.get(0); - Assert.assertEquals("Test5 - ACLs are expected to match", setACLList, receivedACLList); - - client.delete(path, status.getVersion()); - } - - @Test - public void testZnodeExists() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), - timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", client.getState().isConnected()); - - String path = "/testZnodeExists"; - byte[] data = "test".getBytes(); - - // create a node - logger.info("Create znode " + path); - client.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - // expire the ZKClient session and then call exists method for the path - expireZooKeeperSession(client, timeout); - final AtomicBoolean isDeleted = new AtomicBoolean(false); - final CountDownLatch latch = new CountDownLatch(1); - Stat stat = client.exists(path, new Watcher() { - @Override - public void process(WatchedEvent event) { - if (event.getType() == Watcher.Event.EventType.NodeDeleted) { - isDeleted.set(true); - latch.countDown(); - } - } - }); - Assert.assertNotNull("node with path " + path + " should exists", stat); - - // now delete the znode and verify if the Watcher is called - client.delete(path, stat.getVersion()); - latch.await(5000, TimeUnit.MILLISECONDS); - Assert.assertTrue("The watcher on the node should have been called", isDeleted.get()); - - // calling async exists method and verifying the return values - CountDownLatch latch2 = new CountDownLatch(1); - final int[] rcArray = { -1 }; - final boolean[] statIsnull = { false }; - client.exists(path, null, new StatCallback() { - @Override - public void processResult(int rc, String path, Object ctx, Stat stat) { - CountDownLatch cdlatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statIsnull[0] = (stat == null); - cdlatch.countDown(); - } - }, latch2); - latch2.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.NONODE.intValue()) { - Assert.fail("exists call is supposed to return NONODE rcvalue, but it returned - " - + KeeperException.Code.get(rcArray[0])); - } - Assert.assertTrue("exists is supposed to return null for Stat," - + " since the node is already deleted", statIsnull[0]); - } - - @Test - public void testGetSetData() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), - timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", client.getState().isConnected()); - - String path = "/testGetSetData"; - byte[] data = "test".getBytes(); - - // create a node and call async getData method and verify its return value - logger.info("Create znode " + path); - client.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - CountDownLatch latch = new CountDownLatch(1); - final Stat[] statArray = { null }; - final int[] rcArray = { -1 }; - final byte[][] dataArray = { {} }; - client.getData(path, true, new DataCallback() { - @Override - public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) { - CountDownLatch cdLatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statArray[0] = stat; - dataArray[0] = data; - cdLatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test1 - getData call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - Assert.assertArrayEquals("Test1 - getData output - ", data, dataArray[0]); - Stat stat = statArray[0]; - - // expire the ZKClient session and then call async setData with new data - expireZooKeeperSession(client, timeout); - latch = new CountDownLatch(1); - data = "newtest".getBytes(); - client.setData(path, data, stat.getVersion(), new StatCallback() { - @Override - public void processResult(int rc, String path, Object ctx, Stat stat) { - CountDownLatch cdlatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statArray[0] = stat; - cdlatch.countDown(); - } - }, latch); - Assert.assertTrue("setData operation should have completed successfully", - latch.await(6000, TimeUnit.MILLISECONDS)); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test2 - setData call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - stat = statArray[0]; - - // call getData - byte[] getDataRet = client.getData(path, null, stat); - Assert.assertArrayEquals("Test3 - getData output - ", data, getDataRet); - - // call setdata and then async getData call - data = "newesttest".getBytes(); - stat = client.setData(path, data, stat.getVersion()); - latch = new CountDownLatch(1); - client.getData(path, null, new DataCallback() { - @Override - public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) { - CountDownLatch cdLatch = (CountDownLatch) ctx; - rcArray[0] = rc; - statArray[0] = stat; - dataArray[0] = data; - cdLatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail("Test4 - getData call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - Assert.assertArrayEquals("Test4 - getData output - ", data, dataArray[0]); - stat = statArray[0]; - - client.delete(path, stat.getVersion()); - } - - @Test - public void testGetChildren() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), - timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", client.getState().isConnected()); - - // create a root node - String root = "/testGetChildren"; - byte[] rootData = "root".getBytes(); - logger.info("Create znode " + root); - client.create(root, rootData, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - // create a child1 node - String child1 = root + "/" + "child1"; - logger.info("Create znode " + child1); - byte[] child1Data = "child1".getBytes(); - client.create(child1, child1Data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - // create a child2 node - String child2 = root + "/" + "child2"; - logger.info("Create znode " + child2); - byte[] child2Data = "child2".getBytes(); - client.create(child2, child2Data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - // call getChildren method and verify its return value - Stat rootStat = new Stat(); - List children = client.getChildren(root, null, rootStat); - Assert.assertEquals("Test1 - children size", 2, children.size()); - - // create a child3 node - String child3 = root + "/" + "child3"; - logger.info("Create znode " + child3); - byte[] child3Data = "child3".getBytes(); - client.create(child3, child3Data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - // call getChildren method and verify its return value - children = client.getChildren(root, true, rootStat); - Assert.assertEquals("Test2 - children size", 3, children.size()); - - // call async getChildren method and verify its return value - CountDownLatch latch = new CountDownLatch(1); - final Stat[] statArray = { null }; - final int[] rcArray = { -1 }; - final int[] childrenCount = { 0 }; - client.getChildren(root, null, new Children2Callback() { - @Override - public void processResult(int rc, String path, Object ctx, List children, Stat stat) { - CountDownLatch cdlatch = (CountDownLatch) ctx; - rcArray[0] = rc; - childrenCount[0] = children.size(); - statArray[0] = stat; - cdlatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail( - "Test3 - getChildren call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - Assert.assertEquals("Test3 - children size", 3, childrenCount[0]); - rootStat = statArray[0]; - - // call async getChildren method and verify its return value - latch = new CountDownLatch(1); - client.getChildren(root, true, new Children2Callback() { - @Override - public void processResult(int rc, String path, Object ctx, List children, Stat stat) { - CountDownLatch cdlatch = (CountDownLatch) ctx; - rcArray[0] = rc; - childrenCount[0] = children.size(); - statArray[0] = stat; - cdlatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail( - "Test4 - getChildren call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - Assert.assertEquals("Test4 - children size", 3, childrenCount[0]); - rootStat = statArray[0]; - - // expire the ZKClient session and then call async setData with new data - expireZooKeeperSession(client, timeout); - - // this is after previous session expiry. call getChildren method and verify its return value - children = client.getChildren(root, null, rootStat); - Assert.assertEquals("Test5 - children size", 3, children.size()); - - // create a child4 node - String child4 = root + "/" + "child4"; - logger.info("Create znode " + child4); - byte[] child4Data = "child4".getBytes(); - client.create(child4, child4Data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - // call async getChildren method and verify its return value - latch = new CountDownLatch(1); - client.getChildren(root, null, new Children2Callback() { - @Override - public void processResult(int rc, String path, Object ctx, List children, Stat stat) { - CountDownLatch cdlatch = (CountDownLatch) ctx; - rcArray[0] = rc; - childrenCount[0] = children.size(); - statArray[0] = stat; - cdlatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail( - "Test6 - getChildren call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - Assert.assertEquals("Test6 - children size", 4, childrenCount[0]); - rootStat = statArray[0]; - - // expire the ZKClient session and then call async setData with new data - expireZooKeeperSession(client, timeout); - - // call getChildren method and verify its return value - children = client.getChildren(root, null); - Assert.assertEquals("Test7 - children size", 4, children.size()); - - // call getChildren method and verify its return value - children = client.getChildren(root, true); - Assert.assertEquals("Test8 - children size", 4, children.size()); - - // call async getChildren method and verify its return value - latch = new CountDownLatch(1); - client.getChildren(root, true, new AsyncCallback.ChildrenCallback() { - - @Override - public void processResult(int rc, String path, Object ctx, List children) { - CountDownLatch cdlatch = (CountDownLatch) ctx; - rcArray[0] = rc; - childrenCount[0] = children.size(); - cdlatch.countDown(); - } - }, latch); - latch.await(3000, TimeUnit.MILLISECONDS); - if (rcArray[0] != KeeperException.Code.OK.intValue()) { - Assert.fail( - "Test9 - getChildren call failed because of exception - " + KeeperException.Code.get(rcArray[0])); - } - Assert.assertEquals("Test9 - children size", 4, childrenCount[0]); - } - - @Test - public void testRetryOnCreatingEphemeralZnode() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient( - zkUtil.getZooKeeperConnectString(), timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", - client.getState().isConnected()); - - String path = "/a"; - byte[] data = "test".getBytes(); - - logger.info("Create znode " + path); - client.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); - logger.info("Created znode " + path); - - expireZooKeeperSession(client, timeout); - logger.info("Create znode w/ new session : " + path); - client.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); - logger.info("Created znode w/ new session : " + path); - } - - @Test - public void testRetryAsyncOperations() throws Exception { - final int timeout = 2000; - ZooKeeperClient client = ZooKeeperClient.createConnectedZooKeeperClient( - zkUtil.getZooKeeperConnectString(), timeout, new HashSet(), retryPolicy); - Assert.assertTrue("Client failed to connect an alive ZooKeeper.", - client.getState().isConnected()); - - String path = "/a"; - byte[] data = "test".getBytes(); - - expireZooKeeperSession(client, timeout); - logger.info("Create znode " + path); - final CountDownLatch createLatch = new CountDownLatch(1); - client.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, - new StringCallback() { - - @Override - public void processResult(int rc, String path, Object ctx, String name) { - if (KeeperException.Code.OK.intValue() == rc) { - createLatch.countDown(); - } - } - - }, null); - createLatch.await(); - logger.info("Created znode " + path); - - expireZooKeeperSession(client, timeout); - logger.info("Create znode " + path); - final CountDownLatch create2Latch = new CountDownLatch(1); - client.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, (rc, path1, ctx, name) -> { - if (KeeperException.Code.NODEEXISTS.intValue() == rc) { - create2Latch.countDown(); - } - }, null); - create2Latch.await(); - logger.info("Created znode " + path); - - expireZooKeeperSession(client, timeout); - logger.info("Exists znode " + path); - final CountDownLatch existsLatch = new CountDownLatch(1); - client.exists(path, false, new StatCallback() { - - @Override - public void processResult(int rc, String path, Object ctx, Stat stat) { - if (KeeperException.Code.OK.intValue() == rc) { - existsLatch.countDown(); - } - } - - }, null); - existsLatch.await(); - - expireZooKeeperSession(client, timeout); - final CountDownLatch getLatch = new CountDownLatch(1); - logger.info("Get data from znode " + path); - client.getData(path, false, new DataCallback() { - - @Override - public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) { - if (KeeperException.Code.OK.intValue() == rc) { - getLatch.countDown(); - } - } - - }, null); - getLatch.await(); - - expireZooKeeperSession(client, timeout); - logger.info("Create children under znode " + path); - final CountDownLatch createChildLatch = new CountDownLatch(1); - client.create(path + "/children", data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, - new StringCallback() { - - @Override - public void processResult(int rc, String path, Object ctx, String name) { - if (KeeperException.Code.OK.intValue() == rc) { - createChildLatch.countDown(); - } - } - - }, null); - createChildLatch.await(); - - expireZooKeeperSession(client, timeout); - final CountDownLatch getChildLatch = new CountDownLatch(1); - final AtomicReference> children = - new AtomicReference>(); - client.getChildren(path, false, new Children2Callback() { - - @Override - public void processResult(int rc, String path, Object ctx, List childList, Stat stat) { - if (KeeperException.Code.OK.intValue() == rc) { - children.set(childList); - getChildLatch.countDown(); - } - } - - }, null); - getChildLatch.await(); - Assert.assertNotNull(children.get()); - Assert.assertEquals(1, children.get().size()); - Assert.assertEquals("children", children.get().get(0)); - logger.info("Get children under znode " + path); - - expireZooKeeperSession(client, timeout); - final CountDownLatch deleteChildLatch = new CountDownLatch(1); - client.delete(path + "/children", -1, new VoidCallback() { - - @Override - public void processResult(int rc, String path, Object ctx) { - if (KeeperException.Code.OK.intValue() == rc) { - deleteChildLatch.countDown(); - } - } - - }, null); - deleteChildLatch.await(); - logger.info("Delete children from znode " + path); - } - -} diff --git a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConcurrencyTest.java b/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConcurrencyTest.java deleted file mode 100644 index 07c28c37bfa..00000000000 --- a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConcurrencyTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.slogger; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import org.junit.Test; - -/** - * Test concurrent access to slogger. - */ -public class ConcurrencyTest { - enum Events { - FOOBAR - } - - @Test - public void testConcurrentFlattening() throws Exception { - final int numThreads = 100; - final int numIterations = 10000; - - Slogger slog = new AbstractSlogger(Collections.emptyList()) { - @Override - public Slogger newSlogger(Optional> clazz, Iterable parent) { - return this; - } - @Override - public void doLog(Level level, Enum event, String message, - Throwable throwable, List keyValues) { - for (int i = 0; i < keyValues.size(); i += 2) { - if (!keyValues.get(i).equals(keyValues.get(i + 1))) { - - throw new RuntimeException("Concurrency error"); - } - } - } - }; - - ExecutorService executor = Executors.newFixedThreadPool(numThreads); - List> futures = new ArrayList<>(); - for (int i = 0; i < numThreads; i++) { - futures.add(executor.submit(() -> { - for (int j = 0; j < numIterations; j++) { - String value = "kv" + Thread.currentThread().getId() + "-" + j; - - slog.kv(value, value).info(Events.FOOBAR); - } - })); - } - - for (Future f : futures) { - f.get(60, TimeUnit.SECONDS); - } - } -} diff --git a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConsoleSloggerTest.java b/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConsoleSloggerTest.java deleted file mode 100644 index 0ca3612346c..00000000000 --- a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConsoleSloggerTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.slogger; - -import org.junit.Test; - -/** - * Test console slogger. - * Doesn't actually assert anything, but can be used to eyeball - */ -public class ConsoleSloggerTest { - enum Events { - FOOBAR, - BARFOO - }; - - @Test - public void testBasic() throws Exception { - ConsoleSlogger root = new ConsoleSlogger(); - root.kv("fo\"o", "ba\r \\").info(Events.FOOBAR); - } -} - diff --git a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/MockSlogger.java b/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/MockSlogger.java deleted file mode 100644 index f71465f88e1..00000000000 --- a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/MockSlogger.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.slogger; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -/** - * Mock Slogger. - */ -public class MockSlogger extends AbstractSlogger { - List events = new ArrayList<>(); - - public MockSlogger() { - super(new ArrayList<>()); - } - - private MockSlogger(Iterable parentCtx) { - super(parentCtx); - } - - @Override - protected Slogger newSlogger(Optional> clazz, Iterable parentCtx) { - return new MockSlogger(parentCtx); - } - - @Override - protected void doLog(Level level, Enum event, String message, Throwable throwable, - List keyValues) { - Map tmpKvs = new HashMap<>(); - for (int i = 0; i < keyValues.size(); i += 2) { - tmpKvs.put(keyValues.get(i).toString(), keyValues.get(i + 1)); - } - events.add(new MockEvent(level, event, message, tmpKvs, throwable)); - } - - static class MockEvent { - private final Level level; - private final Enum event; - private final String message; - private final Map kvs; - private final Throwable throwable; - - MockEvent(Level level, Enum event, String message, - Map kvs, Throwable throwable) { - this.level = level; - this.event = event; - this.message = message; - this.kvs = kvs; - this.throwable = throwable; - } - - Level getLevel() { - return level; - } - Enum getEvent() { - return event; - } - String getMessage() { - return message; - } - Map getKeyValues() { - return kvs; - } - Throwable getThrowable() { - return throwable; - } - } -} diff --git a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/SloggerTest.java b/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/SloggerTest.java deleted file mode 100644 index 32bf663d7e2..00000000000 --- a/bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/SloggerTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.slogger; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import org.junit.Test; - -/** - * Test Slogger. - */ -public class SloggerTest { - enum Events { - FOOBAR, - BARFOO - }; - - @Test - public void testBasic() throws Exception { - MockSlogger root = new MockSlogger(); - root.kv("foo", 2324).kv("bar", 2342).info(Events.FOOBAR); - assertThat(root.events, hasSize(1)); - assertThat(root.events.get(0).getLevel(), is(MockSlogger.Level.INFO)); - assertThat(root.events.get(0).getEvent(), is(Events.FOOBAR)); - assertThat(root.events.get(0).getKeyValues(), - allOf(hasEntry("foo", "2324"), - hasEntry("bar", "2342"))); - } - - @Test - public void testSloggable() throws Exception { - MockSlogger root = new MockSlogger(); - root.kv("fancy", new FancyClass(0, 2)).info(Events.FOOBAR); - assertThat(root.events, hasSize(1)); - assertThat(root.events.get(0).getLevel(), is(MockSlogger.Level.INFO)); - assertThat(root.events.get(0).getEvent(), is(Events.FOOBAR)); - assertThat(root.events.get(0).getKeyValues(), - allOf(hasEntry("fancy.foo", "0"), - hasEntry("fancy.bar", "2"), - hasEntry("fancy.baz.baz", "123"))); - } - - @Test - public void testList() throws Exception { - MockSlogger root = new MockSlogger(); - List list = new ArrayList<>(); - list.add(1); - list.add(2); - root.kv("list", list).info(Events.FOOBAR); - - assertThat(root.events, hasSize(1)); - assertThat(root.events.get(0).getLevel(), is(MockSlogger.Level.INFO)); - assertThat(root.events.get(0).getEvent(), is(Events.FOOBAR)); - assertThat(root.events.get(0).getKeyValues(), hasEntry("list", "[1, 2]")); - } - - @Test - public void testMap() throws Exception { - MockSlogger root = new MockSlogger(); - HashMap map = new LinkedHashMap<>(); - map.put(1, 3); - map.put(2, 4); - root.kv("map", map).info(Events.FOOBAR); - - assertThat(root.events, hasSize(1)); - assertThat(root.events.get(0).getLevel(), is(MockSlogger.Level.INFO)); - assertThat(root.events.get(0).getEvent(), is(Events.FOOBAR)); - assertThat(root.events.get(0).getKeyValues(), hasEntry("map", "{1=3, 2=4}")); - } - - @Test - public void testArray() throws Exception { - MockSlogger root = new MockSlogger(); - String[] array = {"foo", "bar"}; - root.kv("array", array).info(Events.FOOBAR); - - assertThat(root.events, hasSize(1)); - assertThat(root.events.get(0).getLevel(), is(MockSlogger.Level.INFO)); - assertThat(root.events.get(0).getEvent(), is(Events.FOOBAR)); - assertThat(root.events.get(0).getKeyValues(), hasEntry("array", "[foo, bar]")); - } - - @Test - public void testNestingLimit() throws Exception { - } - - @Test - public void testCtx() throws Exception { - MockSlogger root = new MockSlogger(); - MockSlogger withCtx = (MockSlogger) root.kv("ctx1", 1234).kv("ctx2", 4321).ctx(); - - withCtx.kv("someMore", 2345).info(Events.FOOBAR); - - assertThat(withCtx.events, hasSize(1)); - assertThat(withCtx.events.get(0).getLevel(), is(MockSlogger.Level.INFO)); - assertThat(withCtx.events.get(0).getEvent(), is(Events.FOOBAR)); - System.out.println("kvs " + withCtx.events.get(0).getKeyValues()); - assertThat(withCtx.events.get(0).getKeyValues(), - allOf(hasEntry("ctx1", "1234"), - hasEntry("ctx2", "4321"), - hasEntry("someMore", "2345"))); - } - - @Test - public void textCtxImmutableAfterCreation() throws Exception { - } - - static class FancyClass implements Sloggable { - int foo; - int bar; - OtherFancyClass baz; - - FancyClass(int foo, int bar) { - this.foo = foo; - this.bar = bar; - this.baz = new OtherFancyClass(123); - } - - @Override - public SloggableAccumulator log(SloggableAccumulator slogger) { - return slogger.kv("foo", foo) - .kv("bar", bar) - .kv("baz", baz); - } - } - - static class OtherFancyClass implements Sloggable { - int baz; - - OtherFancyClass(int baz) { - this.baz = baz; - } - - @Override - public SloggableAccumulator log(SloggableAccumulator slogger) { - return slogger.kv("baz", baz); - } - } -} diff --git a/bookkeeper-slogger/slf4j/src/test/java/org/apache/bookkeeper/slogger/slf4j/Slf4jTest.java b/bookkeeper-slogger/slf4j/src/test/java/org/apache/bookkeeper/slogger/slf4j/Slf4jTest.java deleted file mode 100644 index 848a05cfacf..00000000000 --- a/bookkeeper-slogger/slf4j/src/test/java/org/apache/bookkeeper/slogger/slf4j/Slf4jTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.slogger.slf4j; - -import org.apache.bookkeeper.slogger.Slogger; -import org.junit.Test; - -/** - * Test to eyeball slf4j output. - * Contains no asserts. - */ -public class Slf4jTest { - enum Events { - FOOBAR - } - @Test - public void testBasic() throws Exception { - Slogger slogger = new Slf4jSlogger(Slf4jTest.class); - slogger.kv("foo", 123).kv("bar", 432).info(Events.FOOBAR); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/CommonHashesTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/CommonHashesTest.java deleted file mode 100644 index f69e5991651..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/CommonHashesTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe; - -import static org.junit.Assert.assertEquals; - -import java.nio.charset.Charset; -import org.junit.Test; - -@SuppressWarnings("javadoc") -public class CommonHashesTest { - - private static final Charset ASCII = Charset.forName("ASCII"); - private static final byte[] DIGITS = "123456789".getBytes(ASCII); - - - @Test - public void testCrc32() { - assertEquals(0xcbf43926, CommonHashes.crc32().calculate(DIGITS)); - } - - @Test - public void testCrc32c() { - assertEquals(0xe3069283, CommonHashes.crc32c().calculate(DIGITS)); - } - - @Test - public void testCrc64() { - assertEquals(0x6c40df5f0b497347L, CommonHashes.crc64().calculate(DIGITS)); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/checksum/ChecksumTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/checksum/ChecksumTest.java deleted file mode 100644 index f68b362a1af..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/checksum/ChecksumTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package com.scurrilous.circe.checksum; - -import static com.scurrilous.circe.params.CrcParameters.CRC32C; -import static org.junit.Assert.assertEquals; - -import com.scurrilous.circe.IncrementalIntHash; -import com.scurrilous.circe.IncrementalLongHash; -import com.scurrilous.circe.crc.StandardCrcProvider; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.junit.Test; - -/** - * Verify circe checksum. - */ -public class ChecksumTest { - - @Test - public void testCrc32cValue() { - final byte[] bytes = "Some String".getBytes(); - int checksum = Crc32cIntChecksum.computeChecksum(Unpooled.wrappedBuffer(bytes)); - - assertEquals(608512271, checksum); - } - - @Test - public void testCrc32cValueResume() { - final byte[] bytes = "Some String".getBytes(); - int checksum = Crc32cIntChecksum.resumeChecksum(0, Unpooled.wrappedBuffer(bytes), 0, bytes.length); - - assertEquals(608512271, checksum); - } - - @Test - public void testCrc32cValueIncremental() { - final byte[] bytes = "Some String".getBytes(); - - int checksum = Crc32cIntChecksum.computeChecksum(Unpooled.wrappedBuffer(bytes)); - assertEquals(608512271, checksum); - - checksum = Crc32cIntChecksum.computeChecksum(Unpooled.wrappedBuffer(bytes, 0, 1)); - for (int i = 1; i < bytes.length; i++) { - checksum = Crc32cIntChecksum.resumeChecksum(checksum, Unpooled.wrappedBuffer(bytes), i, 1); - } - assertEquals(608512271, checksum); - - checksum = Crc32cIntChecksum.computeChecksum(Unpooled.wrappedBuffer(bytes, 0, 4)); - checksum = Crc32cIntChecksum.resumeChecksum(checksum, Unpooled.wrappedBuffer(bytes), 4, 7); - assertEquals(608512271, checksum); - - - ByteBuf buffer = Unpooled.wrappedBuffer(bytes, 0, 4); - checksum = Crc32cIntChecksum.computeChecksum(buffer); - checksum = Crc32cIntChecksum.resumeChecksum( - checksum, Unpooled.wrappedBuffer(bytes), 4, bytes.length - 4); - - assertEquals(608512271, checksum); - } - - @Test - public void testCrc32cLongValue() { - final byte[] bytes = "Some String".getBytes(); - long checksum = Crc32cIntChecksum.computeChecksum(Unpooled.wrappedBuffer(bytes)); - - assertEquals(608512271L, checksum); - } - - @Test - public void testCrc32cLongValueResume() { - final byte[] bytes = "Some String".getBytes(); - long checksum = Crc32cIntChecksum.resumeChecksum(0, Unpooled.wrappedBuffer(bytes), 0, bytes.length); - - assertEquals(608512271L, checksum); - } - - @Test - public void testCRC32CIncrementalLong() { - IncrementalLongHash crc32c = new StandardCrcProvider().getIncrementalLong(CRC32C); - String data = "data"; - String combine = data + data; - - long combineChecksum = crc32c.calculate(combine.getBytes()); - long dataChecksum = crc32c.calculate(data.getBytes()); - long incrementalChecksum = crc32c.resume(dataChecksum, data.getBytes()); - assertEquals(combineChecksum, incrementalChecksum); - } - - @Test - public void testCRC32CIncrementalInt() { - IncrementalIntHash crc32c = new StandardCrcProvider().getIncrementalInt(CRC32C); - String data = "data"; - String combine = data + data; - - int combineChecksum = crc32c.calculate(combine.getBytes()); - int dataChecksum = crc32c.calculate(data.getBytes()); - int incrementalChecksum = crc32c.resume(dataChecksum, data.getBytes()); - assertEquals(combineChecksum, incrementalChecksum); - } - -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/checksum/Java9IntHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/checksum/Java9IntHashTest.java deleted file mode 100644 index 3fb57b4a1aa..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/checksum/Java9IntHashTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package com.scurrilous.circe.checksum; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.CompositeByteBuf; -import io.netty.buffer.DuplicatedByteBuf; -import java.util.Random; -import lombok.extern.slf4j.Slf4j; -import org.junit.Assert; -import org.junit.Test; - -@Slf4j -public class Java9IntHashTest { - - private ByteBuf[] generateByteBuffers() { - Random random = new Random(); - int hugeDataLen = 4096 * 3; - byte[] hugeData = new byte[hugeDataLen]; - for (int i = 0; i < hugeDataLen; i ++) { - hugeData[i] = (byte) (random.nextInt() % 127); - } - - // b_total = b1 + b2 + b3; - ByteBuf bTotal = ByteBufAllocator.DEFAULT.heapBuffer(6 + hugeDataLen); - bTotal.writeBytes(new byte[]{1,2,3,4,5,6}); - bTotal.writeBytes(hugeData); - ByteBuf b1 = ByteBufAllocator.DEFAULT.heapBuffer(3); - b1.writeBytes(new byte[]{1,2,3}); - ByteBuf b2 = ByteBufAllocator.DEFAULT.heapBuffer(3); - b2.writeBytes(new byte[]{4,5,6}); - ByteBuf b3 = ByteBufAllocator.DEFAULT.heapBuffer(hugeDataLen); - b3.writeBytes(hugeData); - - return new ByteBuf[]{bTotal, b1, new CompositeByteBuf(ByteBufAllocator.DEFAULT, false, 2, b2, b3)}; - } - - @Test - public void calculateCheckSumUsingCompositeByteBuf() { - // byteBuffers[0] = byteBuffers[1] + byteBuffers[2]. - // byteBuffers[2] is a composite ByteBuf. - ByteBuf[] byteBuffers = generateByteBuffers(); - ByteBuf bTotal = byteBuffers[0]; - ByteBuf b1 = byteBuffers[1]; - ByteBuf b2 = byteBuffers[2]; - - // Calculate: case-1. - int checksumRes1 = Crc32cIntChecksum.computeChecksum(bTotal); - - // Calculate: case-2. - int b1CheckSum = Crc32cIntChecksum.computeChecksum(b1); - int checksumRes2 = Crc32cIntChecksum.resumeChecksum(b1CheckSum, b2); - - // Verify: the results of both ways to calculate the checksum are same. - Assert.assertEquals(checksumRes1, checksumRes2); - - // cleanup. - bTotal.release(); - b1.release(); - b2.release(); - } - - @Test - public void calculateCheckSumUsingNoArrayNoMemoryAddrByteBuf() { - // byteBuffers[0] = byteBuffers[1] + byteBuffers[2]. - // byteBuffers[2] is a composite ByteBuf. - ByteBuf[] byteBuffers = generateByteBuffers(); - ByteBuf bTotal = byteBuffers[0]; - ByteBuf b1 = byteBuffers[1]; - ByteBuf b2 = new NoArrayNoMemoryAddrByteBuff(byteBuffers[2]); - - // Calculate: case-1. - int checksumRes1 = Crc32cIntChecksum.computeChecksum(bTotal); - - // Calculate: case-2. - int b1CheckSum = Crc32cIntChecksum.computeChecksum(b1); - int checksumRes2 = Crc32cIntChecksum.resumeChecksum(b1CheckSum, b2); - - // Verify: the results of both ways to calculate the checksum are same. - Assert.assertEquals(checksumRes1, checksumRes2); - - // cleanup. - bTotal.release(); - b1.release(); - b2.release(); - } - - public static class NoArrayNoMemoryAddrByteBuff extends DuplicatedByteBuf { - - public NoArrayNoMemoryAddrByteBuff(ByteBuf buffer) { - super(buffer); - } - - @Override - public boolean hasArray(){ - return false; - } - - @Override - public boolean hasMemoryAddress(){ - return false; - } - } -} \ No newline at end of file diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCProvidersTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCProvidersTest.java deleted file mode 100644 index 81ff710f6a8..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCProvidersTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe.crc; - -import static com.scurrilous.circe.HashSupport.HARDWARE; -import static com.scurrilous.circe.HashSupport.INCREMENTAL; -import static com.scurrilous.circe.HashSupport.INT_SIZED; -import static com.scurrilous.circe.HashSupport.LONG_SIZED; -import static com.scurrilous.circe.HashSupport.NATIVE; -import static com.scurrilous.circe.HashSupport.STATEFUL; -import static com.scurrilous.circe.HashSupport.STATELESS_INCREMENTAL; -import static com.scurrilous.circe.params.CrcParameters.CRC32; -import static com.scurrilous.circe.params.CrcParameters.CRC64; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.EnumSet; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.SortedMap; - -import com.scurrilous.circe.HashProvider; -import com.scurrilous.circe.HashProviders; -import com.scurrilous.circe.HashSupport; -import com.scurrilous.circe.IncrementalLongHash; -import org.junit.Test; - -@SuppressWarnings("javadoc") -public class CRCProvidersTest { - - @Test - public void testAll() { - final Iterator i = HashProviders.iterator(); - assertTrue(i.hasNext()); - assertTrue(i.next() instanceof StandardCrcProvider); - assertFalse(i.hasNext()); - } - - @Test - public void testNonUnique() { - final HashProvider provider = HashProviders.best(CRC32); - final IncrementalLongHash i1 = provider.getIncrementalLong(CRC32); - final IncrementalLongHash i2 = provider.getIncrementalLong(CRC32); - assertTrue(i1 != i2); - } - - @Test - public void testSearchCRCParametersCRC32() { - final SortedMap, HashProvider> map = HashProviders.search(CRC32); - assertEquals(1, map.size()); - final Entry, HashProvider> entry = map.entrySet().iterator().next(); - assertEquals(EnumSet.of(NATIVE, STATELESS_INCREMENTAL, INCREMENTAL, INT_SIZED, LONG_SIZED, - STATEFUL), entry.getKey()); - assertTrue(entry.getValue() instanceof StandardCrcProvider); - } - - @Test - public void testSearchCRCParametersCRC64() { - final SortedMap, HashProvider> map = HashProviders.search(CRC64); - assertEquals(1, map.size()); - final Entry, HashProvider> entry = map.entrySet().iterator().next(); - assertEquals(EnumSet.of(STATELESS_INCREMENTAL, INCREMENTAL, LONG_SIZED, STATEFUL), - entry.getKey()); - assertTrue(entry.getValue() instanceof StandardCrcProvider); - } - - @Test - public void testSearchCRCParametersEnumSet() { - assertEquals(1, HashProviders.search(CRC32, EnumSet.of(NATIVE)).size()); - assertTrue(HashProviders.search(CRC64, EnumSet.of(NATIVE)).isEmpty()); - assertTrue(HashProviders.search(CRC32, EnumSet.of(HARDWARE)).isEmpty()); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCTest.java deleted file mode 100644 index 287026c8fec..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe.crc; - -import static com.scurrilous.circe.params.CrcParameters.CRC16; -import static com.scurrilous.circe.params.CrcParameters.CRC16_CCITT; -import static com.scurrilous.circe.params.CrcParameters.CRC16_XMODEM; -import static com.scurrilous.circe.params.CrcParameters.CRC32; -import static com.scurrilous.circe.params.CrcParameters.CRC32C; -import static com.scurrilous.circe.params.CrcParameters.CRC32_BZIP2; -import static com.scurrilous.circe.params.CrcParameters.CRC32_POSIX; -import static com.scurrilous.circe.params.CrcParameters.CRC64; -import static com.scurrilous.circe.params.CrcParameters.CRC64_XZ; -import static org.junit.Assert.assertEquals; - -import com.scurrilous.circe.IncrementalLongHash; -import com.scurrilous.circe.HashProvider; -import com.scurrilous.circe.IncrementalIntHash; -import com.scurrilous.circe.params.CrcParameters; -import java.nio.charset.Charset; -import org.junit.Test; - -/** - * Tests the {@link StandardCrcProvider} with various CRC algorithms. See the Catalogue of parametrised - * CRC algorithms for more information on these algorithms and others. - */ -@SuppressWarnings("javadoc") -public class CRCTest { - - private static final HashProvider PROVIDER = new StandardCrcProvider(); - private static final Charset ASCII = Charset.forName("ASCII"); - private static final byte[] DIGITS = "123456789".getBytes(ASCII); - - @Test - public void testCRC3_ROHC() { - final CrcParameters CRC3_ROHC = new CrcParameters("CRC-3/ROHC", 3, 0x3, 0x7, 0, true); - assertEquals(0x6, PROVIDER.getIncrementalInt(CRC3_ROHC).calculate(DIGITS)); - } - - @Test - public void testCRC5_EPC() { - final CrcParameters CRC5_EPC = new CrcParameters("CRC-5/EPC", 5, 0x09, 0x09, 0, false); - assertEquals(0x00, PROVIDER.getIncrementalInt(CRC5_EPC).calculate(DIGITS)); - } - - @Test - public void testCRC5_USB() { - final CrcParameters CRC5_USB = new CrcParameters("CRC-5/USB", 5, 0x05, 0x1f, 0x1f, true); - assertEquals(0x19, PROVIDER.getIncrementalInt(CRC5_USB).calculate(DIGITS)); - } - - @Test - public void testCRC7() { - final CrcParameters CRC7 = new CrcParameters("CRC-7", 7, 0x09, 0, 0, false); - assertEquals(0x75, PROVIDER.getIncrementalInt(CRC7).calculate(DIGITS)); - } - - @Test - public void testCRC7ROHC() { - final CrcParameters CRC7_ROHC = new CrcParameters("CRC-7/ROHC", 7, 0x4f, 0x7f, 0, true); - assertEquals(0x53, PROVIDER.getIncrementalInt(CRC7_ROHC).calculate(DIGITS)); - } - - @Test - public void testCRC8() { - final CrcParameters CRC8 = new CrcParameters("CRC-8", 8, 0x07, 0, 0, false); - assertEquals(0xf4, PROVIDER.getIncrementalInt(CRC8).calculate(DIGITS)); - } - - @Test - public void testCRC10() { - final CrcParameters CRC10 = new CrcParameters("CRC-10", 10, 0x233, 0, 0, false); - assertEquals(0x199, PROVIDER.getIncrementalInt(CRC10).calculate(DIGITS)); - } - - @Test - public void testCRC15() { - final CrcParameters CRC15 = new CrcParameters("CRC-15", 15, 0x4599, 0, 0, false); - assertEquals(0x059e, PROVIDER.getIncrementalInt(CRC15).calculate(DIGITS)); - } - - @Test - public void testCRC16() { - assertEquals(0xbb3d, PROVIDER.getIncrementalInt(CRC16).calculate(DIGITS)); - } - - @Test - public void testCRC16_CCITT() { - assertEquals(0x2189, PROVIDER.getIncrementalInt(CRC16_CCITT).calculate(DIGITS)); - } - - @Test - public void testXMODEM() { - assertEquals(0x31c3, PROVIDER.getIncrementalInt(CRC16_XMODEM).calculate(DIGITS)); - } - - @Test - public void testCRC24() { - final CrcParameters CRC24 = new CrcParameters("CRC-24", 24, 0x864cfb, 0xb704ce, 0, false); - assertEquals(0x21cf02, PROVIDER.getIncrementalInt(CRC24).calculate(DIGITS)); - } - - @Test - public void testCRC32() { - assertEquals(0xcbf43926, PROVIDER.getIncrementalInt(CRC32).calculate(DIGITS)); - } - - @Test - public void testJavaCRC32() { - assertEquals(0xcbf43926, PROVIDER.getStatelessInt(CRC32).calculate(DIGITS)); - } - - @Test - public void testBZIP2() { - assertEquals(0xfc891918, PROVIDER.getIncrementalInt(CRC32_BZIP2).calculate(DIGITS)); - } - - @Test - public void testCRC32C() { - assertEquals(0xe3069283, PROVIDER.getIncrementalInt(CRC32C).calculate(DIGITS)); - } - - @Test - public void testCRC32D() { - final CrcParameters CRC32D = new CrcParameters("CRC-32D", 32, 0xa833982b, ~0, ~0, true); - assertEquals(0x87315576, PROVIDER.getIncrementalInt(CRC32D).calculate(DIGITS)); - } - - @Test - public void testPOSIX() { - assertEquals(0x765e7680, PROVIDER.getIncrementalInt(CRC32_POSIX).calculate(DIGITS)); - } - - @Test - public void testCRC32Q() { - final CrcParameters CRC32Q = new CrcParameters("CRC-32Q", 32, 0x814141ab, 0, 0, false); - assertEquals(0x3010bf7f, PROVIDER.getIncrementalInt(CRC32Q).calculate(DIGITS)); - } - - @Test - public void testCRC64() { - assertEquals(0x6c40df5f0b497347L, PROVIDER.getIncrementalLong(CRC64).calculate(DIGITS)); - } - - @Test - public void testCRC64_XZ() { - assertEquals(0x995dc9bbdf1939faL, PROVIDER.getIncrementalLong(CRC64_XZ).calculate(DIGITS)); - } - - @Test - public void testCRC32CIncrementalInt() { - // reflected - testIncrementalInt(PROVIDER.getIncrementalInt(CRC32C)); - } - - private void testIncrementalInt(IncrementalIntHash hash) { - final String data = "data"; - final String combined = data + data; - - final int dataChecksum = hash.calculate(data.getBytes(ASCII)); - final int combinedChecksum = hash.calculate(combined.getBytes(ASCII)); - final int incrementalChecksum = hash.resume(dataChecksum, data.getBytes(ASCII)); - assertEquals(combinedChecksum, incrementalChecksum); - } - - @Test - public void testCRC32CIncrementalLong() { - // reflected - testIncrementalLong(PROVIDER.getIncrementalLong(CRC32C)); - } - - private void testIncrementalLong(IncrementalLongHash hash) { - final String data = "data"; - final String combined = data + data; - - final long dataChecksum = hash.calculate(data.getBytes(ASCII)); - final long combinedChecksum = hash.calculate(combined.getBytes(ASCII)); - final long incrementalChecksum = hash.resume(dataChecksum, data.getBytes(ASCII)); - assertEquals(combinedChecksum, incrementalChecksum); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalIntHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalIntHashTest.java deleted file mode 100644 index 7b75a03dfd0..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalIntHashTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.scurrilous.circe.StatefulHash; -import java.nio.ByteBuffer; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -@SuppressWarnings("javadoc") -public class AbstractIncrementalIntHashTest { - - private AbstractIncrementalIntHash hash; - - @Before - public void setup() { - this.hash = mock(AbstractIncrementalIntHash.class, Mockito.CALLS_REAL_METHODS); - } - - @Test - public void testAsStateful() { - final byte[] input = new byte[10]; - - when(hash.initial()).thenReturn(42); - when(hash.resumeUnchecked(eq(42), eq(input), eq(2), eq(4))).thenReturn(99); - - StatefulHash stateful = hash.createStateful(); - stateful.algorithm(); - stateful.length(); - assertNotSame(stateful, stateful.createNew()); - stateful.reset(); - stateful.update(input, 2, 4); - assertEquals(99, stateful.getInt()); - - // verification - verify(hash, times(1)).algorithm(); - verify(hash, times(1)).length(); - verify(hash, times(1)).initial(); - verify(hash, times(1)).resumeUnchecked( - eq(42), eq(input), eq(2), eq(4)); - } - - @Test - public void testCalculateByteArray() { - final byte[] input = new byte[10]; - - when(hash.initial()).thenReturn(42); - - hash.calculate(input); - - verify(hash, times(1)).initial(); - verify(hash, times(1)).resume(eq(42), eq(input)); - } - - @Test - public void testCalculateByteArrayIntInt() { - final byte[] input = new byte[10]; - - when(hash.initial()).thenReturn(42); - - hash.calculate(input, 2, 4); - - verify(hash, times(1)).initial(); - verify(hash, times(1)).resume(eq(42), eq(input), eq(2), eq(4)); - } - - @Test - public void testCalculateByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(10); - - when(hash.initial()).thenReturn(42); - - hash.calculate(input); - - verify(hash, times(1)).initial(); - verify(hash, times(1)).resume(eq(42), eq(input)); - } - - @Test - public void testResumeIntByteArray() { - final byte[] input = new byte[10]; - - hash.resume(42, input); - - verify(hash, times(1)).resumeUnchecked(eq(42), eq(input), eq(0), eq(input.length)); - } - - @Test - public void testResumeIntByteArrayIntInt() { - final byte[] input = new byte[10]; - - hash.resume(42, input, 2, 4); - - verify(hash, times(1)).resumeUnchecked(eq(42), eq(input), eq(2), eq(4)); - } - - @Test - public void testResumeIntByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20); - input.position(5); - input.limit(15); - - hash.resume(42, input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .resumeUnchecked(eq(42), eq(input.array()), eq(input.arrayOffset() + 5), eq(10)); - } - - @Test - public void testResumeIntReadOnlyByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer(); - input.position(5); - input.limit(15); - - hash.resume(42, input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .resumeUnchecked(eq(42), any(byte[].class), eq(0), eq(10)); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalLongHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalLongHashTest.java deleted file mode 100644 index 81f8f72ebd3..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalLongHashTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.scurrilous.circe.StatefulHash; -import java.nio.ByteBuffer; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -@SuppressWarnings("javadoc") -public class AbstractIncrementalLongHashTest { - - private AbstractIncrementalLongHash hash; - - @Before - public void setup() { - this.hash = mock(AbstractIncrementalLongHash.class, Mockito.CALLS_REAL_METHODS); - } - - @Test - public void testAsStateful() { - final byte[] input = new byte[10]; - - when(hash.initial()).thenReturn(0x4200000000L); - when(hash.resumeUnchecked(eq(0x4200000000L), eq(input), eq(2), eq(4))) - .thenReturn(0x990000000000L); - - StatefulHash stateful = hash.createStateful(); - stateful.algorithm(); - stateful.length(); - assertNotSame(stateful, stateful.createNew()); - stateful.reset(); - stateful.update(input, 2, 4); - assertEquals(0, stateful.getInt()); - assertEquals(0x990000000000L, stateful.getLong()); - - verify(hash, times(1)).algorithm(); - verify(hash, times(1)).length(); - verify(hash, times(1)).initial(); - verify(hash, times(1)).resumeUnchecked( - eq(0x4200000000L), eq(input), eq(2), eq(4)); - } - - @Test - public void testCalculateByteArray() { - final byte[] input = new byte[10]; - - when(hash.initial()).thenReturn(0x4200000000L); - - hash.calculate(input); - - verify(hash, times(1)).resume(eq(0x4200000000L), eq(input)); - } - - @Test - public void testCalculateByteArrayIntInt() { - final byte[] input = new byte[10]; - - when(hash.initial()).thenReturn(0x4200000000L); - - hash.calculate(input, 2, 4); - - verify(hash, times(1)).resume(eq(0x4200000000L), eq(input), eq(2), eq(4)); - } - - @Test - public void testCalculateByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(10); - - when(hash.initial()).thenReturn(0x4200000000L); - - hash.calculate(input); - - verify(hash, times(1)).resume(eq(0x4200000000L), eq(input)); - } - - @Test - public void testResumeLongByteArray() { - final byte[] input = new byte[10]; - - hash.resume(0x4200000000L, input); - - verify(hash, times(1)) - .resumeUnchecked(eq(0x4200000000L), eq(input), eq(0), eq(input.length)); - } - - @Test - public void testResumeLongByteArrayIntInt() { - final byte[] input = new byte[10]; - - hash.resume(0x4200000000L, input, 2, 4); - - verify(hash, times(1)) - .resumeUnchecked(eq(0x4200000000L), eq(input), eq(2), eq(4)); - } - - @Test - public void testResumeLongByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20); - input.position(5); - input.limit(15); - - hash.resume(0x4200000000L, input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .resumeUnchecked(eq(0x4200000000L), eq(input.array()), eq(input.arrayOffset() + 5), eq(10)); - } - - @Test - public void testResumeLongReadOnlyByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer(); - input.position(5); - input.limit(15); - - hash.resume(0x4200000000L, input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .resumeUnchecked(eq(0x4200000000L), any(byte[].class), eq(0), eq(10)); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatefulHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatefulHashTest.java deleted file mode 100644 index 039dd5c05d0..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatefulHashTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe.impl; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import org.junit.Test; -import org.mockito.Mockito; - -@SuppressWarnings("javadoc") -public class AbstractStatefulHashTest { - - private AbstractStatefulHash hash; - - public AbstractStatefulHashTest() { - this.hash = mock(AbstractStatefulHash.class, Mockito.CALLS_REAL_METHODS); - } - - @Test - public void testUpdateByteArray() { - final byte[] input = new byte[42]; - - hash.update(input); - - verify(hash, times(1)) - .updateUnchecked(eq(input), eq(0), eq(input.length)); - } - - @Test - public void testUpdateByteArrayIntInt() { - final byte[] input = new byte[42]; - - hash.update(input, 5, 10); - - verify(hash, times(1)) - .updateUnchecked(eq(input), eq(5), eq(10)); - } - - @Test(expected = IllegalArgumentException.class) - public void testUpdateByteArrayIntNegInt() { - final byte[] input = new byte[42]; - - hash.update(input, 1, -1); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testUpdateByteArrayNegIntInt() { - final byte[] input = new byte[42]; - - hash.update(input, -1, 10); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testUpdateByteArrayIntIntOverflow() { - final byte[] input = new byte[42]; - - hash.update(input, 40, 3); - } - - @Test - public void testUpdateByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20); - input.position(5); - input.limit(15); - - hash.update(input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .updateUnchecked(eq(input.array()), eq(input.arrayOffset() + 5), eq(10)); - } - - @Test - public void testUpdateReadOnlyByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer(); - input.position(5); - input.limit(15); - - hash.update(input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .updateUnchecked(any(byte[].class), eq(0), eq(10)); - } - - @Test - public void testGetBytes() { - final List captures = new ArrayList<>(); - - when(hash.length()).thenReturn(5); - - doAnswer(invocationOnMock -> { - captures.add(invocationOnMock.getArgument(0)); - return invocationOnMock.callRealMethod(); - }).when(hash).writeBytes(any(byte[].class), eq(0), eq(5)); - - hash.getBytes(); - assertEquals(5, captures.get(0).length); - } - - @Test - public void testGetBytesByteArrayInt() { - final byte[] output = new byte[5]; - - when(hash.length()).thenReturn(output.length); - when(hash.getLong()).thenReturn(0x1234567890L); - - hash.getBytes(output, 0, output.length); - assertArrayEquals(new byte[] { (byte) 0x90, 0x78, 0x56, 0x34, 0x12 }, output); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testGetBytesByteArrayNegInt() { - final byte[] output = new byte[5]; - - when(hash.length()).thenReturn(output.length); - - hash.getBytes(output, -1, output.length); - - verify(hash, atLeast(0)).length(); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testGetBytesByteArrayIntOverflow() { - final byte[] output = new byte[5]; - - hash.getBytes(output, 0, output.length + 1); - } - - @Test - public void testGetBytesByteArrayIntPartial() { - final byte[] output = new byte[5]; - - when(hash.length()).thenReturn(output.length + 1); - - hash.getBytes(output, 0, output.length); - - verify(hash, times(1)).writeBytes(eq(output), eq(0), eq(output.length)); - } - - @Test - public void testGetByte() { - when(hash.getInt()).thenReturn(0x12345678); - - assertEquals(0x78, hash.getByte()); - } - - @Test - public void testGetShort() { - when(hash.getInt()).thenReturn(0x12345678); - - assertEquals(0x5678, hash.getShort()); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessIntHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessIntHashTest.java deleted file mode 100644 index 69fc4f79e18..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessIntHashTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe.impl; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.nio.ByteBuffer; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -@SuppressWarnings("javadoc") -public class AbstractStatelessIntHashTest { - - private AbstractStatelessIntHash hash; - - @Before - public void setup() { - hash = mock(AbstractStatelessIntHash.class, Mockito.CALLS_REAL_METHODS); - } - - @Test - public void testCalculateByteArray() { - final byte[] input = new byte[10]; - - hash.calculate(input); - - verify(hash, times(1)).calculateUnchecked(eq(input), eq(0), eq(input.length)); - } - - @Test - public void testCalculateByteArrayIntInt() { - final byte[] input = new byte[10]; - - hash.calculate(input, 2, 4); - - verify(hash, times(1)).calculateUnchecked(eq(input), eq(2), eq(4)); - } - - @Test - public void testCalculateByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20); - input.position(5); - input.limit(15); - - hash.calculate(input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .calculateUnchecked(eq(input.array()), eq(input.arrayOffset() + 5), eq(10)); - } - - @Test - public void testCalculateReadOnlyByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer(); - input.position(5); - input.limit(15); - - hash.calculate(input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .calculateUnchecked(any(byte[].class), eq(0), eq(10)); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessLongHashTest.java b/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessLongHashTest.java deleted file mode 100644 index 0b05e2e4218..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessLongHashTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Trevor Robinson - * - * Licensed 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. - ******************************************************************************/ -package com.scurrilous.circe.impl; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.nio.ByteBuffer; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -@SuppressWarnings("javadoc") -public class AbstractStatelessLongHashTest { - - private AbstractStatelessLongHash hash; - - @Before - public void setup() { - this.hash = mock(AbstractStatelessLongHash.class, Mockito.CALLS_REAL_METHODS); - } - - @Test - public void testCalculateByteArray() { - final byte[] input = new byte[10]; - - hash.calculate(input); - - verify(hash, times(1)) - .calculateUnchecked(eq(input), eq(0), eq(input.length)); - } - - @Test - public void testCalculateByteArrayIntInt() { - final byte[] input = new byte[10]; - - hash.calculate(input, 2, 4); - - verify(hash, times(1)) - .calculateUnchecked(eq(input), eq(2), eq(4)); - } - - @Test - public void testCalculateByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20); - input.position(5); - input.limit(15); - - hash.calculate(input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .calculateUnchecked(eq(input.array()), eq(input.arrayOffset() + 5), eq(10)); - } - - @Test - public void testCalculateReadOnlyByteBuffer() { - final ByteBuffer input = ByteBuffer.allocate(20).asReadOnlyBuffer(); - input.position(5); - input.limit(15); - - hash.calculate(input); - assertEquals(input.limit(), input.position()); - - verify(hash, times(1)) - .calculateUnchecked(any(byte[].class), eq(0), eq(10)); - } -} diff --git a/circe-checksum/src/test/java/com/scurrilous/circe/utils/NativeUtilsTests.java b/circe-checksum/src/test/java/com/scurrilous/circe/utils/NativeUtilsTests.java deleted file mode 100644 index 17bb45ace2a..00000000000 --- a/circe-checksum/src/test/java/com/scurrilous/circe/utils/NativeUtilsTests.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package com.scurrilous.circe.utils; - -import java.io.FileNotFoundException; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test of {@link NativeUtils}. - */ -public class NativeUtilsTests { - - @Test - public void testLoadLibrary() throws Exception { - - final String fileName = "test" + NativeUtils.libType(); - try { - NativeUtils.loadLibraryFromJar(fileName); - Assert.fail("Should fail because of not having absolute path"); - } catch (IllegalArgumentException e) { - // OK - } - - try { - NativeUtils.loadLibraryFromJar("/" + fileName); - Assert.fail("Should fail because no file present into the jar"); - } catch (FileNotFoundException e) { - // OK - } - } - -} diff --git a/cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/CpuInfoTest.java b/cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/CpuInfoTest.java deleted file mode 100644 index bcb3bcd1c3f..00000000000 --- a/cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/CpuInfoTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.common.util.affinity.impl; - -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Sets; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.util.stream.Collectors; -import org.junit.Test; - -/** - * Tests for CpuInfo class. - */ -public class CpuInfoTest { - - @Test - public void testParseCpuInfo() throws Exception { - try (BufferedReader r = new BufferedReader( - new InputStreamReader(CpuInfoTest.class.getResourceAsStream("/proc_cpuinfo.txt")))) { - String text = r.lines().collect(Collectors.joining("\n")); - - ProcessorsInfo pi = ProcessorsInfo.parseCpuInfo(text); - - assertEquals(Sets.newHashSet(0, 12), pi.getCpusOnSameCore(0)); - assertEquals(Sets.newHashSet(0, 12), pi.getCpusOnSameCore(12)); - - assertEquals(Sets.newHashSet(8, 20), pi.getCpusOnSameCore(8)); - assertEquals(Sets.newHashSet(8, 20), pi.getCpusOnSameCore(20)); - } - } -} diff --git a/cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/IsolatedProcessorsTest.java b/cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/IsolatedProcessorsTest.java deleted file mode 100644 index eb3d1b21566..00000000000 --- a/cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/IsolatedProcessorsTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.common.util.affinity.impl; - -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Sets; -import org.junit.Test; - -/** - * Tests for {@link IsolatedProcessors}. - */ -public class IsolatedProcessorsTest { - - @Test - public void testParseProcessors() throws Exception { - assertEquals(Sets.newHashSet(), IsolatedProcessors.parseProcessorRange("")); - - assertEquals(Sets.newHashSet(1, 3, 4, 5, 6, 7), IsolatedProcessors.parseProcessorRange("1,3-7")); - - assertEquals(Sets.newHashSet(1), IsolatedProcessors.parseProcessorRange("1")); - assertEquals(Sets.newHashSet(1, 3), IsolatedProcessors.parseProcessorRange("1,3")); - assertEquals(Sets.newHashSet(1, 3, 4, 5, 6, 7, 10, 11, 12, 13), - IsolatedProcessors.parseProcessorRange("1,3-7,10-13")); - - assertEquals(Sets.newHashSet(1, 3, 4, 5, 6, 7), IsolatedProcessors.parseProcessorRange("1,3-7\n")); - } -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/Etcd64bitIdGeneratorTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/Etcd64bitIdGeneratorTest.java deleted file mode 100644 index fff2f2264ed..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/Etcd64bitIdGeneratorTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.util.concurrent.RateLimiter; -import io.etcd.jetcd.Client; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallbackFuture; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.Before; -import org.junit.Test; - -/** - * Integration test {@link Etcd64bitIdGenerator}. - */ -@Slf4j -public class Etcd64bitIdGeneratorTest extends EtcdTestBase { - - private String scope; - private Etcd64bitIdGenerator generator; - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - this.scope = "/" + RandomStringUtils.randomAlphabetic(8); - this.generator = new Etcd64bitIdGenerator(etcdClient.getKVClient(), scope); - log.info("Setup id generator under scope {}", scope); - } - - @Test - public void testGenerateIdSequence() throws Exception { - Map buckets = new HashMap<>(); - - int numIterations = 10; - - for (int i = 0; i < numIterations; i++) { - log.info("Id generation iteration : {}", i); - for (int j = 0; j < Etcd64bitIdGenerator.NUM_BUCKETS; j++) { - GenericCallbackFuture future = new GenericCallbackFuture<>(); - generator.generateLedgerId(future); - long lid = future.get(); - int bucketId = Etcd64bitIdGenerator.getBucketId(lid); - long idInBucket = Etcd64bitIdGenerator.getIdInBucket(lid); - Long prevIdInBucket = buckets.put(bucketId, idInBucket); - if (null == prevIdInBucket) { - assertEquals(1, idInBucket); - } else { - assertEquals(prevIdInBucket + 1, idInBucket); - } - } - } - - assertEquals(Etcd64bitIdGenerator.NUM_BUCKETS, buckets.size()); - for (Map.Entry bucketEntry : buckets.entrySet()) { - assertEquals(numIterations, bucketEntry.getValue().intValue()); - } - } - - /** - * Test generating id in parallel and ensure there is no duplicated id. - */ - @Test - public void testGenerateIdParallel() throws Exception { - final int numThreads = 10; - @Cleanup("shutdown") - ExecutorService executor = Executors.newFixedThreadPool(numThreads); - - final int numIds = 10000; - final AtomicLong totalIds = new AtomicLong(numIds); - final Set ids = Collections.newSetFromMap(new ConcurrentHashMap<>()); - final RateLimiter limiter = RateLimiter.create(1000); - final CompletableFuture doneFuture = new CompletableFuture<>(); - for (int i = 0; i < numThreads; i++) { - executor.submit(() -> { - Client client = Client.builder() - .endpoints(etcdContainer.getClientEndpoint()) - .build(); - Etcd64bitIdGenerator gen = new Etcd64bitIdGenerator( - client.getKVClient(), - scope - ); - - AtomicBoolean running = new AtomicBoolean(true); - - while (running.get()) { - limiter.acquire(); - - GenericCallbackFuture genFuture = new GenericCallbackFuture<>(); - gen.generateLedgerId(genFuture); - - genFuture - .thenAccept(lid -> { - boolean duplicatedFound = !(ids.add(lid)); - if (duplicatedFound) { - running.set(false); - doneFuture.completeExceptionally( - new IllegalStateException("Duplicated id " + lid + " generated : " + ids)); - return; - } else { - if (totalIds.decrementAndGet() <= 0) { - running.set(false); - doneFuture.complete(null); - } - } - }) - .exceptionally(cause -> { - running.set(false); - doneFuture.completeExceptionally(cause); - return null; - }); - } - }); - } - - FutureUtils.result(doneFuture); - assertTrue(totalIds.get() <= 0); - assertTrue(ids.size() >= numIds); - } - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdClusterTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdClusterTest.java deleted file mode 100644 index 3f2d99e0a75..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdClusterTest.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getBookiesPath; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getBucketsPath; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getClusterInstanceIdPath; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getLayoutKey; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getLedgersPath; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getReadonlyBookiesPath; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getScopeEndKey; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getUnderreplicationPath; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.getWritableBookiesPath; -import static org.apache.bookkeeper.metadata.etcd.EtcdUtils.msResult; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.etcd.jetcd.ByteSequence; -import io.etcd.jetcd.Client; -import io.etcd.jetcd.kv.GetResponse; -import io.etcd.jetcd.options.GetOption; -import java.util.UUID; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.BookieException.MetadataStoreException; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.LedgerLayout; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Test cluster related operation on Etcd based registration manager. - */ -@Slf4j -public class EtcdClusterTest extends EtcdTestBase { - - private String scope; - private RegistrationManager regMgr; - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - this.scope = RandomStringUtils.randomAlphabetic(32); - this.regMgr = new EtcdRegistrationManager( - newEtcdClient(), scope - ); - } - - @After - @Override - public void tearDown() throws Exception { - this.regMgr.close(); - super.tearDown(); - } - - @Test - public void testGetClusterInstanceIdIfClusterNotInitialized() throws Exception { - try { - regMgr.getClusterInstanceId(); - fail("Should fail getting cluster instance id if cluster not initialized"); - } catch (MetadataStoreException e) { - assertTrue(e.getMessage().contains("BookKeeper is not initialized")); - } - } - - @Test - public void testGetClusterInstanceId() throws Exception { - assertClusterNotExists(etcdClient, scope); - regMgr.initNewCluster(); - String instanceId = regMgr.getClusterInstanceId(); - UUID uuid = UUID.fromString(instanceId); - log.info("Cluster instance id : {}", uuid); - } - - @Test - public void testNukeNonExistingCluster() throws Exception { - assertClusterNotExists(etcdClient, scope); - assertTrue(regMgr.nukeExistingCluster()); - assertClusterNotExists(etcdClient, scope); - } - - @Test - public void testNukeExistingCluster() throws Exception { - assertTrue(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - assertTrue(regMgr.nukeExistingCluster()); - assertClusterNotExists(etcdClient, scope); - } - - @Test - public void testInitNewClusterTwice() throws Exception { - assertTrue(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - String instanceId = regMgr.getClusterInstanceId(); - assertFalse(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - assertEquals(instanceId, regMgr.getClusterInstanceId()); - } - - @Test - public void testPrepareFormatNonExistingCluster() throws Exception { - assertFalse(regMgr.prepareFormat()); - } - - @Test - public void testPrepareFormatExistingCluster() throws Exception { - assertTrue(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - assertTrue(regMgr.prepareFormat()); - } - - @Test - public void testNukeExistingClusterWithWritableBookies() throws Exception { - testNukeExistingClusterWithBookies(false); - } - - @Test - public void testNukeExistingClusterWithReadonlyBookies() throws Exception { - testNukeExistingClusterWithBookies(true); - } - - private void testNukeExistingClusterWithBookies(boolean readonly) throws Exception { - assertTrue(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - createNumBookies(etcdClient, scope, 3, readonly); - assertFalse(regMgr.nukeExistingCluster()); - assertClusterExists(etcdClient, scope); - removeNumBookies(etcdClient, scope, 3, readonly); - assertTrue(regMgr.nukeExistingCluster()); - assertClusterNotExists(etcdClient, scope); - } - - @Test - public void testNukeExistingClusterWithAllBookies() throws Exception { - assertTrue(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - createNumBookies(etcdClient, scope, 1, false); - createNumBookies(etcdClient, scope, 2, true); - assertFalse(regMgr.nukeExistingCluster()); - assertClusterExists(etcdClient, scope); - removeNumBookies(etcdClient, scope, 1, false); - removeNumBookies(etcdClient, scope, 2, true); - assertTrue(regMgr.nukeExistingCluster()); - assertClusterNotExists(etcdClient, scope); - } - - @Test - public void testFormatNonExistingCluster() throws Exception { - assertClusterNotExists(etcdClient, scope); - assertTrue(regMgr.format()); - assertClusterExists(etcdClient, scope); - } - - @Test - public void testFormatExistingCluster() throws Exception { - assertClusterNotExists(etcdClient, scope); - assertTrue(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - String clusterInstanceId = regMgr.getClusterInstanceId(); - assertTrue(regMgr.format()); - assertClusterExists(etcdClient, scope); - assertNotEquals(clusterInstanceId, regMgr.getClusterInstanceId()); - } - - @Test - public void testFormatExistingClusterWithBookies() throws Exception { - assertClusterNotExists(etcdClient, scope); - assertTrue(regMgr.initNewCluster()); - assertClusterExists(etcdClient, scope); - String clusterInstanceId = regMgr.getClusterInstanceId(); - createNumBookies(etcdClient, scope, 3, false); - assertFalse(regMgr.format()); - assertClusterExists(etcdClient, scope); - assertEquals(clusterInstanceId, regMgr.getClusterInstanceId()); - } - - private static void createNumBookies(Client client, - String scope, - int numBookies, - boolean readonly) throws Exception { - for (int i = 0; i < numBookies; i++) { - BookieId bookieId = BookieId.parse("bookie-" + i + ":3181"); - String bookiePath; - if (readonly) { - bookiePath = EtcdUtils.getReadonlyBookiePath(scope, bookieId); - } else { - bookiePath = EtcdUtils.getWritableBookiePath(scope, bookieId); - } - msResult(client.getKVClient().put( - ByteSequence.from(bookiePath, UTF_8), - EtcdConstants.EMPTY_BS - )); - } - } - - private static void removeNumBookies(Client client, - String scope, - int numBookies, - boolean readonly) throws Exception { - for (int i = 0; i < numBookies; i++) { - BookieId bookieId = BookieId.parse("bookie-" + i + ":3181"); - String bookiePath; - if (readonly) { - bookiePath = EtcdUtils.getReadonlyBookiePath(scope, bookieId); - } else { - bookiePath = EtcdUtils.getWritableBookiePath(scope, bookieId); - } - msResult(client.getKVClient().delete( - ByteSequence.from(bookiePath, UTF_8) - )); - } - } - - private static void assertClusterScope(Client client, - String scope) throws Exception { - GetResponse resp = msResult( - client.getKVClient().get( - ByteSequence.from(scope, UTF_8))); - assertEquals(1, resp.getCount()); - } - - private static void assertClusterLayout(Client client, - String scope) throws Exception { - String layoutPath = getLayoutKey(scope); - GetResponse resp = msResult( - client.getKVClient().get( - ByteSequence.from(layoutPath, UTF_8))); - assertEquals(1, resp.getCount()); - LedgerLayout layout = LedgerLayout.parseLayout( - resp.getKvs().get(0).getValue().getBytes() - ); - assertEquals( - EtcdLedgerManagerFactory.class.getName(), - layout.getManagerFactoryClass() - ); - assertEquals(EtcdLedgerManagerFactory.VERSION, layout.getManagerVersion()); - assertEquals(LedgerLayout.LAYOUT_FORMAT_VERSION, layout.getLayoutFormatVersion()); - } - - private static void assertClusterInstanceId(Client client, - String scope) throws Exception { - String instanceIdPath = getClusterInstanceIdPath(scope); - GetResponse resp = msResult( - client.getKVClient().get(ByteSequence.from(instanceIdPath, UTF_8))); - assertEquals(1, resp.getCount()); - String instanceId = new String(resp.getKvs().get(0).getValue().getBytes(), UTF_8); - UUID uuid = UUID.fromString(instanceId); - log.info("Cluster instance id : {}", uuid); - } - - private static void assertBookiesPath(Client client, - String scope) throws Exception { - String bookiesPath = getBookiesPath(scope); - GetResponse resp = msResult( - client.getKVClient().get(ByteSequence.from(bookiesPath, UTF_8))); - assertEquals(1, resp.getCount()); - } - - private static void assertWritableBookiesPath(Client client, - String scope) throws Exception { - String bookiesPath = getWritableBookiesPath(scope); - GetResponse resp = msResult( - client.getKVClient().get(ByteSequence.from(bookiesPath, UTF_8))); - assertEquals(1, resp.getCount()); - } - - private static void assertReadonlyBookiesPath(Client client, - String scope) throws Exception { - String bookiesPath = getReadonlyBookiesPath(scope); - GetResponse resp = msResult( - client.getKVClient().get(ByteSequence.from(bookiesPath, UTF_8))); - assertEquals(1, resp.getCount()); - } - - private static void assertLedgersPath(Client client, String scope) throws Exception { - String ledgersPath = getLedgersPath(scope); - GetResponse resp = msResult( - client.getKVClient().get(ByteSequence.from(ledgersPath, UTF_8))); - assertEquals(1, resp.getCount()); - } - - private static void assertBucketsPath(Client client, String scope) throws Exception { - String bucketsPath = getBucketsPath(scope); - GetResponse resp = msResult( - client.getKVClient().get(ByteSequence.from(bucketsPath, UTF_8))); - assertEquals(1, resp.getCount()); - } - - private static void assertUnderreplicationPath(Client client, String scope) throws Exception { - String urPath = getUnderreplicationPath(scope); - GetResponse resp = msResult( - client.getKVClient().get(ByteSequence.from(urPath, UTF_8))); - assertEquals(1, resp.getCount()); - } - - private static void assertClusterExists(Client client, String scope) throws Exception { - assertClusterScope(client, scope); - assertClusterLayout(client, scope); - assertClusterInstanceId(client, scope); - assertBookiesPath(client, scope); - assertWritableBookiesPath(client, scope); - assertReadonlyBookiesPath(client, scope); - assertLedgersPath(client, scope); - assertBucketsPath(client, scope); - assertUnderreplicationPath(client, scope); - } - - private static void assertClusterNotExists(Client client, String scope) throws Exception { - GetResponse response = msResult( - client.getKVClient().get( - ByteSequence.from(scope, UTF_8), - GetOption.newBuilder() - .withRange(ByteSequence.from(getScopeEndKey(scope), UTF_8)) - .build())); - assertEquals(0, response.getCount()); - } - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdCookieTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdCookieTest.java deleted file mode 100644 index c9d1a412e4a..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdCookieTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.BookieException.CookieNotFoundException; -import org.apache.bookkeeper.bookie.BookieException.MetadataStoreException; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Version.Occurred; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Test Etcd based cookie management. - */ -@Slf4j -public class EtcdCookieTest extends EtcdTestBase { - - @Rule - public final TestName runtime = new TestName(); - - private RegistrationManager regMgr; - - @Before - @Override - public void setUp() throws Exception { - log.info("setup"); - super.setUp(); - String scope = RandomStringUtils.randomAlphabetic(16); - this.regMgr = new EtcdRegistrationManager( - newEtcdClient(), - scope - ); - log.info("done setup"); - } - - @After - @Override - public void tearDown() throws Exception { - log.info("tear down"); - this.regMgr.close(); - super.tearDown(); - } - - private static void assertCookieEquals(Versioned expected, Versioned actual) { - assertEquals(Occurred.CONCURRENTLY, expected.getVersion().compare(actual.getVersion())); - assertArrayEquals(expected.getValue(), actual.getValue()); - } - - @Test - public void readWriteRemoveCookie() throws Exception { - BookieId bookieId = BookieId.parse(runtime.getMethodName() + ":3181"); - - log.info("read non-existing cookie"); - // read the cookie doesn't exist - try { - regMgr.readCookie(bookieId); - fail("Should fail reading cookie if cookie doesn't exist"); - } catch (CookieNotFoundException cnfe) { - // expected - } - - log.info("create cookie"); - // create the cookie - String cookieData = RandomStringUtils.randomAlphanumeric(1024); - Versioned cookie = new Versioned<>( - cookieData.getBytes(UTF_8), Version.NEW - ); - regMgr.writeCookie(bookieId, cookie); - - log.info("read cookie"); - // read the cookie - Versioned readCookie = regMgr.readCookie(bookieId); - assertEquals(cookieData, new String(readCookie.getValue(), UTF_8)); - - log.info("try to create cookie again"); - // attempt to create the cookie again - String newCookieData = RandomStringUtils.randomAlphabetic(512); - Versioned newCookie = new Versioned<>( - newCookieData.getBytes(UTF_8), Version.NEW - ); - try { - regMgr.writeCookie(bookieId, newCookie); - fail("Should fail creating cookie if the cookie already exists"); - } catch (MetadataStoreException mse) { - assertTrue(mse.getMessage().contains("Conflict on writing cookie")); - } - Versioned readCookie2 = regMgr.readCookie(bookieId); - assertCookieEquals(readCookie, readCookie2); - - log.info("update cookie with wrong version"); - // attempt to update the cookie with a wrong version - newCookie = new Versioned<>( - newCookieData.getBytes(UTF_8), new LongVersion(Long.MAX_VALUE) - ); - try { - regMgr.writeCookie(bookieId, newCookie); - } catch (MetadataStoreException mse) { - assertTrue(mse.getMessage().contains("Conflict on writing cookie")); - } - readCookie2 = regMgr.readCookie(bookieId); - assertCookieEquals(readCookie, readCookie2); - - log.info("delete cookie with wrong version"); - // delete the cookie with a wrong version - LongVersion badVersion = new LongVersion(Long.MAX_VALUE); - try { - regMgr.removeCookie(bookieId, badVersion); - fail("Should fail to remove cookie with bad version"); - } catch (MetadataStoreException mse) { - assertTrue(mse.getMessage().contains( - "bad version '" + badVersion + "'" - )); - } - readCookie2 = regMgr.readCookie(bookieId); - assertCookieEquals(readCookie, readCookie2); - - log.info("update with right version"); - // update the cookie with right version - newCookie = new Versioned<>( - newCookieData.getBytes(UTF_8), readCookie2.getVersion()); - regMgr.writeCookie(bookieId, newCookie); - readCookie2 = regMgr.readCookie(bookieId); - assertEquals(newCookieData, new String(readCookie2.getValue(), UTF_8)); - assertEquals(Occurred.AFTER, readCookie2.getVersion().compare(readCookie.getVersion())); - - log.info("delete with right version"); - // delete the cookie with right version - regMgr.removeCookie(bookieId, readCookie2.getVersion()); - try { - regMgr.readCookie(bookieId); - fail("Should fail reading cookie if cookie doesn't exist"); - } catch (CookieNotFoundException cnfe) { - // expected - } - - log.info("remove non-existing cookie"); - // remove a cookie that doesn't exist - try { - regMgr.removeCookie(bookieId, readCookie2.getVersion()); - fail("Should fail removing cookie if cookie doesn't exist"); - } catch (CookieNotFoundException cnfe) { - // expected - } - } - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLayoutManagerTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLayoutManagerTest.java deleted file mode 100644 index a0a1f696c49..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLayoutManagerTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd; - -import static org.apache.bookkeeper.metadata.etcd.EtcdConstants.LAYOUT_NODE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import java.io.IOException; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.meta.LayoutManager.LedgerLayoutExistsException; -import org.apache.bookkeeper.meta.LedgerLayout; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.Before; -import org.junit.Test; - -/** - * Integration test {@link EtcdLayoutManager}. - */ -@Slf4j -public class EtcdLayoutManagerTest extends EtcdTestBase { - - private static final int managerVersion = 0xabcd; - - private String scope; - private EtcdLayoutManager layoutManager; - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - this.scope = "/" + RandomStringUtils.randomAlphabetic(8); - this.layoutManager = new EtcdLayoutManager(etcdClient, scope); - log.info("setup layout manager under scope {}", scope); - } - - @Test - public void testReadCreateDeleteLayout() throws Exception { - // layout doesn't exist - assertNull(layoutManager.readLedgerLayout()); - - // create the layout - LedgerLayout layout = new LedgerLayout( - EtcdLedgerManagerFactory.class.getName(), - managerVersion - ); - layoutManager.storeLedgerLayout(layout); - - // read the layout - LedgerLayout readLayout = layoutManager.readLedgerLayout(); - assertEquals(layout, readLayout); - - // attempts to create the layout again and it should fail - LedgerLayout newLayout = new LedgerLayout( - "new layout", - managerVersion + 1 - ); - try { - layoutManager.storeLedgerLayout(newLayout); - fail("Should fail storeLedgerLayout if layout already exists"); - } catch (LedgerLayoutExistsException e) { - // expected - } - - // read the layout again (layout should not be changed) - readLayout = layoutManager.readLedgerLayout(); - assertEquals(layout, readLayout); - - // delete the layout - layoutManager.deleteLedgerLayout(); - - // the layout should be gone now - assertNull(layoutManager.readLedgerLayout()); - - // delete the layout again. it should fail since layout doesn't exist - try { - layoutManager.deleteLedgerLayout(); - fail("Should fail deleteLedgerLayout is layout not found"); - } catch (IOException ioe) { - assertEquals( - "No ledger layout is found under '" + scope + "/" + LAYOUT_NODE + "'", - ioe.getMessage()); - } - } - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLedgerManagerTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLedgerManagerTest.java deleted file mode 100644 index f206817b6cd..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLedgerManagerTest.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Licensed 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. - */ - -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.metadata.etcd; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.meta.LedgerManager.LedgerRange; -import org.apache.bookkeeper.meta.LedgerManager.LedgerRangeIterator; -import org.apache.bookkeeper.metadata.etcd.helpers.ValueStream; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.LedgerMetadataListener; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Integration test {@link EtcdLedgerManager}. - */ -@Slf4j -public class EtcdLedgerManagerTest extends EtcdTestBase { - - private String scope; - private EtcdLedgerManager lm; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - this.scope = RandomStringUtils.randomAlphabetic(8); - this.lm = new EtcdLedgerManager(etcdClient, scope); - } - - @Override - @After - public void tearDown() throws Exception { - if (null != lm) { - lm.close(); - } - super.tearDown(); - } - - @Test - public void testLedgerCRUD() throws Exception { - long ledgerId = System.currentTimeMillis(); - List ensemble = Lists.newArrayList( - BookieId.parse("192.0.2.1:1234"), - BookieId.parse("192.0.2.2:1234"), - BookieId.parse("192.0.2.3:1234")); - LedgerMetadata metadata = LedgerMetadataBuilder.create().withId(ledgerId) - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .withPassword("test-password".getBytes(UTF_8)) - .withDigestType(DigestType.CRC32C.toApiDigestType()) - .newEnsembleEntry(0L, ensemble) - .build(); - - // ledger doesn't exist: read - try { - result(lm.readLedgerMetadata(ledgerId)); - fail("Should fail on reading ledger metadata if the ledger doesn't exist"); - } catch (BKException bke) { - assertEquals(Code.NoSuchLedgerExistsException, bke.getCode()); - } - - // ledger doesn't exist : delete - try { - result(lm.removeLedgerMetadata(ledgerId, new LongVersion(999L))); - fail("Should fail on deleting ledger metadata if the ledger doesn't exist"); - } catch (BKException bke) { - assertEquals(Code.NoSuchLedgerExistsException, bke.getCode()); - } - - // ledger doesn't exist : write - try { - result(lm.writeLedgerMetadata(ledgerId, metadata, new LongVersion(999L))); - fail("Should fail on updating ledger metadata if the ledger doesn't exist"); - } catch (BKException bke) { - assertEquals(Code.NoSuchLedgerExistsException, bke.getCode()); - } - - // ledger doesn't exist : create - Versioned writtenMetadata = result(lm.createLedgerMetadata(ledgerId, metadata)); - assertSame(metadata, writtenMetadata.getValue()); - Version version = writtenMetadata.getVersion(); - assertNotNull(version); - assertTrue(version instanceof LongVersion); - assertTrue(((LongVersion) version).getLongVersion() > 0L); - - // ledger exists : create - - // attempt to create the ledger again will result in exception `LedgerExistsException` - try { - result(lm.createLedgerMetadata(ledgerId, metadata)); - fail("Should fail on creating ledger metadata if the ledger already exists"); - } catch (BKException bke) { - assertEquals(Code.LedgerExistException, bke.getCode()); - } - - // ledger exists: get - Versioned readMetadata = result(lm.readLedgerMetadata(ledgerId)); - assertEquals(metadata, readMetadata.getValue()); - - // ledger exists: update metadata with wrong version - try { - result(lm.writeLedgerMetadata(ledgerId, readMetadata.getValue(), new LongVersion(Long.MAX_VALUE))); - fail("Should fail to write metadata using a wrong version"); - } catch (BKException bke) { - assertEquals(Code.MetadataVersionException, bke.getCode()); - } - readMetadata = result(lm.readLedgerMetadata(ledgerId)); - assertEquals(metadata, readMetadata.getValue()); - - // ledger exists: delete metadata with wrong version - try { - result(lm.removeLedgerMetadata(ledgerId, new LongVersion(Long.MAX_VALUE))); - fail("Should fail to delete metadata using a wrong version"); - } catch (BKException bke) { - assertEquals(Code.MetadataVersionException, bke.getCode()); - } - - readMetadata = result(lm.readLedgerMetadata(ledgerId)); - assertEquals(metadata, readMetadata.getValue()); - - // ledger exists: update metadata with the right version - - LongVersion curVersion = (LongVersion) readMetadata.getVersion(); - writtenMetadata = result(lm.writeLedgerMetadata(ledgerId, readMetadata.getValue(), curVersion)); - LongVersion newVersion = (LongVersion) writtenMetadata.getVersion(); - assertTrue(curVersion.getLongVersion() < newVersion.getLongVersion()); - - readMetadata = result(lm.readLedgerMetadata(ledgerId)); - assertEquals(writtenMetadata, readMetadata); - - // ledger exists: delete metadata with the right version - result(lm.removeLedgerMetadata(ledgerId, newVersion)); - try { - result(lm.readLedgerMetadata(ledgerId)); - fail("Should fail to read ledger if it is deleted"); - } catch (BKException bke) { - assertEquals(Code.NoSuchLedgerExistsException, bke.getCode()); - } - - } - - @Test - public void testProcessLedgers() throws Exception { - final int numLedgers = 100; - createNumLedgers(numLedgers); - - final CountDownLatch processLatch = new CountDownLatch(numLedgers); - final CompletableFuture doneFuture = new CompletableFuture<>(); - lm.asyncProcessLedgers( - (l, cb) -> processLatch.countDown(), - (rc, path, ctx) -> { - if (Code.OK == rc) { - FutureUtils.complete(doneFuture, null); - } else { - FutureUtils.completeExceptionally(doneFuture, BKException.create(rc)); - } - }, - null, - Code.OK, - Code.MetaStoreException); - - result(doneFuture); - processLatch.await(); - } - - @Test - public void testLedgerRangeIterator() throws Exception { - final int numLedgers = 100; - createNumLedgers(numLedgers); - - long nextLedgerId = 0L; - LedgerRangeIterator iter = lm.getLedgerRanges(0); - while (iter.hasNext()) { - LedgerRange lr = iter.next(); - for (Long lid : lr.getLedgers()) { - assertEquals(nextLedgerId, lid.longValue()); - ++nextLedgerId; - } - } - assertEquals((long) numLedgers, nextLedgerId); - } - - private void createNumLedgers(int numLedgers) throws Exception { - List>> createFutures = new ArrayList<>(numLedgers); - for (int i = 0; i < numLedgers; i++) { - LedgerMetadata metadata = LedgerMetadataBuilder.create().withId(i) - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .withPassword("test-password".getBytes(UTF_8)) - .withDigestType(DigestType.CRC32C.toApiDigestType()) - .newEnsembleEntry(0L, createNumBookies(3)).build(); - createFutures.add(lm.createLedgerMetadata(i, metadata)); - } - FutureUtils.result(FutureUtils.collect(createFutures)); - } - - @Test - public void testRegisterLedgerMetadataListener() throws Exception { - long ledgerId = System.currentTimeMillis(); - - // create a ledger metadata - LedgerMetadata metadata = LedgerMetadataBuilder.create().withId(ledgerId) - .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2) - .withPassword("test-password".getBytes(UTF_8)) - .withDigestType(DigestType.CRC32C.toApiDigestType()) - .newEnsembleEntry(0L, createNumBookies(3)).build(); - result(lm.createLedgerMetadata(ledgerId, metadata)); - Versioned readMetadata = lm.readLedgerMetadata(ledgerId).get(); - log.info("Create ledger metadata : {}", readMetadata.getValue()); - - // register first listener - - LinkedBlockingQueue> metadataQueue1 = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener1 = (lid, m) -> { - log.info("[listener1] Received ledger {} metadata : {}", lid, m); - metadataQueue1.add(m); - }; - log.info("Registered first listener for ledger {}", ledgerId); - lm.registerLedgerMetadataListener(ledgerId, listener1); - // we should receive a metadata notification when a ledger is created - Versioned notifiedMetadata = metadataQueue1.take(); - assertEquals(readMetadata, notifiedMetadata); - ValueStream lms = lm.getLedgerMetadataStream(ledgerId); - assertNotNull(lms.waitUntilWatched()); - assertNotNull(result(lms.waitUntilWatched())); - - // register second listener - - LinkedBlockingQueue> metadataQueue2 = new LinkedBlockingQueue<>(); - LedgerMetadataListener listener2 = (lid, m) -> { - log.info("[listener2] Received ledger {} metadata : {}", lid, m); - metadataQueue2.add(m); - }; - log.info("Registered second listener for ledger {}", ledgerId); - lm.registerLedgerMetadataListener(ledgerId, listener2); - Versioned notifiedMetadata2 = metadataQueue2.take(); - assertEquals(readMetadata, notifiedMetadata2); - assertNotNull(lm.getLedgerMetadataStream(ledgerId)); - - // update the metadata - lm.writeLedgerMetadata(ledgerId, - LedgerMetadataBuilder.from(metadata).newEnsembleEntry(10L, createNumBookies(3)).build(), - notifiedMetadata.getVersion()).get(); - readMetadata = lm.readLedgerMetadata(ledgerId).get(); - assertEquals(readMetadata, metadataQueue1.take()); - assertEquals(readMetadata, metadataQueue2.take()); - lms = lm.getLedgerMetadataStream(ledgerId); - assertNotNull(lms); - assertEquals(2, lms.getNumConsumers()); - - // remove listener2 - lm.unregisterLedgerMetadataListener(ledgerId, listener2); - lms = lm.getLedgerMetadataStream(ledgerId); - assertNotNull(lms); - assertEquals(1, lms.getNumConsumers()); - - // update the metadata again - lm.writeLedgerMetadata(ledgerId, - LedgerMetadataBuilder.from(metadata).newEnsembleEntry(20L, createNumBookies(3)).build(), - readMetadata.getVersion()).get(); - readMetadata = lm.readLedgerMetadata(ledgerId).get(); - assertEquals(readMetadata, metadataQueue1.take()); - assertNull(metadataQueue2.poll()); - - // remove listener1 - lm.unregisterLedgerMetadataListener(ledgerId, listener1); - // the value stream will be removed - while (lm.getLedgerMetadataStream(ledgerId) != null) { - TimeUnit.MILLISECONDS.sleep(100); - } - assertEquals(0, lms.getNumConsumers()); - - // update the metadata again - lm.writeLedgerMetadata(ledgerId, - LedgerMetadataBuilder.from(metadata).newEnsembleEntry(30L, createNumBookies(3)).build(), - readMetadata.getVersion()).get(); - readMetadata = lm.readLedgerMetadata(ledgerId).get(); - assertNull(metadataQueue1.poll()); - assertNull(metadataQueue2.poll()); - - log.info("Registered first listener for ledger {} again", ledgerId); - lm.registerLedgerMetadataListener(ledgerId, listener1); - notifiedMetadata = metadataQueue1.take(); - assertEquals(readMetadata, notifiedMetadata); - lms = lm.getLedgerMetadataStream(ledgerId); - assertNotNull(lms); - assertEquals(1, lms.getNumConsumers()); - - // delete the ledger - lm.removeLedgerMetadata(ledgerId, readMetadata.getVersion()).get(); - // the listener will eventually be removed - while (lm.getLedgerMetadataStream(ledgerId) != null) { - TimeUnit.MILLISECONDS.sleep(100); - } - assertEquals(1, lms.getNumConsumers()); - assertNull(metadataQueue1.poll()); - assertNull(metadataQueue2.poll()); - } - - static List createNumBookies(int numBookies) { - return IntStream.range(0, numBookies) - .mapToObj(idx -> BookieId.parse("127.0.0.1:" + (3181 + idx))) - .collect(Collectors.toList()); - } -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdRegistrationTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdRegistrationTest.java deleted file mode 100644 index d9cf7a5086e..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdRegistrationTest.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Sets; -import io.etcd.jetcd.Client; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicInteger; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieException.MetadataStoreException; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.discover.BookieServiceInfo; -import org.apache.bookkeeper.discover.RegistrationClient; -import org.apache.bookkeeper.discover.RegistrationClient.RegistrationListener; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Version.Occurred; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Test etcd based bookie registration. - */ -@Slf4j -public class EtcdRegistrationTest extends EtcdTestBase { - - static BookieId newBookie(int i) { - return BookieId.parse("127.0.0.1:" + (3181 + i)); - } - - @Rule - public final TestName runtime = new TestName(); - - private String scope; - private RegistrationClient regClient; - - protected static RegistrationListener newRegistrationListener( - LinkedBlockingQueue>> notifications) { - return bookies -> { - log.info("Received new bookies: {}", bookies); - try { - notifications.put(bookies); - } catch (InterruptedException e) { - log.error("Interrupted at enqueuing updated key set", e); - } - }; - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - this.scope = RandomStringUtils.randomAlphabetic(16); - this.regClient = new EtcdRegistrationClient(scope, etcdClient); - } - - @After - @Override - public void tearDown() throws Exception { - this.regClient.close(); - super.tearDown(); - } - - interface MultiBookiesTester { - - void test(String scope, int numBookies, boolean readonly) throws Exception; - - } - - private static void runNumBookiesTest(final String scope, - final int numBookies, - final boolean readonly, - MultiBookiesTester tester) throws Exception { - - final List bookies = createNumBookies(readonly, numBookies, scope); - try { - tester.test(scope, numBookies, readonly); - } finally { - bookies.forEach(EtcdRegistrationManager::close); - } - - } - - @Test - public void testRegisterWritableBookies() throws Exception { - testRegisterBookie(false); - } - - @Test - public void testRegisterReadonlyBookies() throws Exception { - testRegisterBookie(true); - } - - private void testRegisterBookie(boolean readonly) throws Exception { - runNumBookiesTest(scope, 3, readonly, (scope, numBookies, ro) -> { - Set expectedBookies = Sets.newHashSet(); - for (int i = 0; i < numBookies; i++) { - expectedBookies.add(newBookie(i)); - } - Set writableBookies = result(regClient.getWritableBookies()).getValue(); - Set readonlyBookies = result(regClient.getReadOnlyBookies()).getValue(); - if (ro) { - assertEquals(0, writableBookies.size()); - assertEquals(numBookies, readonlyBookies.size()); - assertEquals(expectedBookies, readonlyBookies); - } else { - assertEquals(0, readonlyBookies.size()); - assertEquals(numBookies, writableBookies.size()); - assertEquals(expectedBookies, writableBookies); - } - - }); - } - - @Test - public void testWatchWritableBookies() throws Exception { - testWatchBookies(false); - } - - @Test - public void testWatchReadonlyBookies() throws Exception { - testWatchBookies(true); - } - - private void testWatchBookies(boolean readonly) throws Exception { - LinkedBlockingQueue>> writableChanges = new LinkedBlockingQueue<>(); - LinkedBlockingQueue>> readonlyChanges = new LinkedBlockingQueue<>(); - result(regClient.watchReadOnlyBookies(newRegistrationListener(readonlyChanges))); - result(regClient.watchWritableBookies(newRegistrationListener(writableChanges))); - Versioned> versionedBookies = writableChanges.take(); - assertTrue(versionedBookies.getValue().isEmpty()); - versionedBookies = readonlyChanges.take(); - assertTrue(versionedBookies.getValue().isEmpty()); - - final int numBookies = 3; - final List bookies = createNumBookies(readonly, numBookies, scope, 1); - - LinkedBlockingQueue>> changes; - if (readonly) { - changes = readonlyChanges; - } else { - changes = writableChanges; - } - - Version preVersion = new LongVersion(-1); - Set expectedBookies = new HashSet<>(); - for (int i = 0; i < numBookies; i++) { - BookieId address = newBookie(i); - expectedBookies.add(address); - - versionedBookies = changes.take(); - Version curVersion = versionedBookies.getVersion(); - assertEquals(Occurred.AFTER, curVersion.compare(preVersion)); - assertEquals(expectedBookies, versionedBookies.getValue()); - preVersion = curVersion; - } - - bookies.forEach(EtcdRegistrationManager::close); - for (int i = 0; i < numBookies; i++) { - versionedBookies = changes.take(); - Version curVersion = versionedBookies.getVersion(); - assertEquals(Occurred.AFTER, curVersion.compare(preVersion)); - assertEquals(numBookies - i - 1, versionedBookies.getValue().size()); - preVersion = curVersion; - } - if (readonly) { - assertEquals(0, writableChanges.size()); - } else { - assertEquals(0, readonlyChanges.size()); - } - } - - private static List createNumBookies(boolean readonly, - int numBookies, - String scope, - long ttlSeconds) throws BookieException { - List bookies = new ArrayList<>(numBookies); - for (int i = 0; i < numBookies; i++) { - Client client = newEtcdClient(); - EtcdRegistrationManager regMgr = new EtcdRegistrationManager(client, scope, ttlSeconds); - bookies.add(regMgr); - regMgr.registerBookie(newBookie(i), readonly, BookieServiceInfo.EMPTY); - } - return bookies; - } - - private static List createNumBookies(boolean readonly, - int numBookies, - String scope) throws BookieException { - return createNumBookies(readonly, numBookies, scope, 60); - } - - @Test - public void testRegisterBookieWaitUntilPreviousExpiredSuccess() throws Exception { - long ttlSeconds = 1; - long leaseId = -0xabcd; - BookieId bookieId = BookieId.parse(runtime.getMethodName() + ":3181"); - try (EtcdRegistrationManager regManager = new EtcdRegistrationManager( - newEtcdClient(), scope, ttlSeconds) - ) { - regManager.registerBookie(bookieId, false, BookieServiceInfo.EMPTY); - leaseId = regManager.getBkRegister().getLeaseId(); - log.info("Registered bookie under scope '{}' with lease = {}", scope, leaseId); - } - assertNotEquals(-0xabcd, leaseId); - final long prevLeaseId = leaseId; - try (EtcdRegistrationManager regManager = new EtcdRegistrationManager( - newEtcdClient(), scope, 100000 * ttlSeconds) - ) { - regManager.registerBookie(bookieId, false, BookieServiceInfo.EMPTY); - leaseId = regManager.getBkRegister().getLeaseId(); - log.info("Registered bookie under scope '{}' with new lease = {}", scope, leaseId); - } - assertNotEquals(prevLeaseId, leaseId); - } - - @Test - public void testRegisterBookieWaitUntilPreviousExpiredFailure() throws Exception { - long ttlSeconds = 1; - long leaseId = -0xabcd; - BookieId bookieId = BookieId.parse(runtime.getMethodName() + ":3181"); - try (EtcdRegistrationManager regManager = new EtcdRegistrationManager( - newEtcdClient(), scope, 10000000 * ttlSeconds) - ) { - regManager.registerBookie(bookieId, false, BookieServiceInfo.EMPTY); - leaseId = regManager.getBkRegister().getLeaseId(); - log.info("Registered bookie under scope '{}' with lease = {}", scope, leaseId); - } - assertNotEquals(-0xabcd, leaseId); - try (EtcdRegistrationManager regManager = new EtcdRegistrationManager( - newEtcdClient(), scope, ttlSeconds) - ) { - regManager.registerBookie(bookieId, false, BookieServiceInfo.EMPTY); - fail("Should fail to register bookie under scope '{}'" - + " since previous registration has not been expired yet"); - } catch (MetadataStoreException mse) { - log.info("Encountered exception on registering bookie under scope '{}'", scope, mse); - // expected - } - } - - @Test - public void testRegisterWritableBookieWithSameLeaseId() throws Exception { - testRegisterBookieWithSameLeaseId(false); - } - - @Test - public void testRegisterReadonlyBookieWithSameLeaseId() throws Exception { - testRegisterBookieWithSameLeaseId(true); - } - - private void testRegisterBookieWithSameLeaseId(boolean readonly) throws Exception { - long ttlSeconds = 1; - long leaseId = -0xabcd; - BookieId bookieId = BookieId.parse(runtime.getMethodName() + ":3181"); - try (EtcdRegistrationManager regManager = new EtcdRegistrationManager( - newEtcdClient(), scope, 10000000 * ttlSeconds) - ) { - regManager.registerBookie(bookieId, readonly, BookieServiceInfo.EMPTY); - leaseId = regManager.getBkRegister().getLeaseId(); - log.info("Registered bookie under scope '{}' with lease = {}", scope, leaseId); - log.info("Trying to register using same lease '{}'", leaseId); - try (EtcdRegistrationManager regManager2 = new EtcdRegistrationManager( - regManager.getClient(), scope, regManager.getBkRegister() - )) { - regManager.registerBookie(bookieId, readonly, BookieServiceInfo.EMPTY); - } - } - } - - private Set getBookies(boolean readonly) throws Exception { - Set bookies; - if (readonly) { - bookies = result(regClient.getReadOnlyBookies()).getValue(); - } else { - bookies = result(regClient.getWritableBookies()).getValue(); - } - return bookies; - } - - @Test - public void testRegisterUnregisterWritableBookie() throws Exception { - testRegisterUnregister(false); - } - - @Test - public void testRegisterUnregisterReadonlyBookie() throws Exception { - testRegisterUnregister(true); - } - - private void testRegisterUnregister(boolean readonly) throws Exception { - String bookieIdStr = runtime.getMethodName(); - if (readonly) { - bookieIdStr += "-readonly"; - } - bookieIdStr += ":3181"; - BookieId bookieId = BookieId.parse(bookieIdStr); - try (EtcdRegistrationManager regMgr = new EtcdRegistrationManager( - newEtcdClient(), scope, 1000000000 - )) { - // before registration - Set bookies = getBookies(readonly); - log.info("before registration : bookies = {}", bookies); - assertEquals(0, bookies.size()); - // registered - regMgr.registerBookie(bookieId, readonly, BookieServiceInfo.EMPTY); - bookies = getBookies(readonly); - log.info("after registered: bookies = {}", bookies); - assertEquals(1, bookies.size()); - assertEquals( - Sets.newHashSet(bookieId), - bookies); - // unregistered - regMgr.unregisterBookie(bookieId, readonly); - bookies = getBookies(readonly); - log.info("after unregistered: bookies = {}", bookies); - assertEquals(0, bookies.size()); - } - } - - @Test - public void testConcurrentWritableRegistration() throws Exception { - testConcurrentRegistration(false); - } - - @Test - public void testConcurrentReadonlyRegistration() throws Exception { - testConcurrentRegistration(true); - } - - private void testConcurrentRegistration(boolean readonly) throws Exception { - final BookieId bookieId; - if (readonly) { - bookieId = BookieId.parse(runtime.getMethodName() + "-readonly:3181"); - } else { - bookieId = BookieId.parse(runtime.getMethodName() + ":3181"); - } - final int numBookies = 10; - @Cleanup("shutdown") - ExecutorService executor = Executors.newFixedThreadPool(numBookies); - final CyclicBarrier startBarrier = new CyclicBarrier(numBookies); - final CyclicBarrier completeBarrier = new CyclicBarrier(numBookies); - final CompletableFuture doneFuture = new CompletableFuture<>(); - final AtomicInteger numSuccesses = new AtomicInteger(0); - final AtomicInteger numFailures = new AtomicInteger(0); - for (int i = 0; i < numBookies; i++) { - executor.submit(() -> { - try (EtcdRegistrationManager regMgr = new EtcdRegistrationManager( - newEtcdClient(), scope, 1 - )) { - try { - startBarrier.await(); - regMgr.registerBookie(bookieId, readonly, BookieServiceInfo.EMPTY); - numSuccesses.incrementAndGet(); - } catch (InterruptedException e) { - log.warn("Interrupted at waiting for the other threads to start", e); - } catch (BrokenBarrierException e) { - log.warn("Start barrier is broken", e); - } catch (BookieException e) { - numFailures.incrementAndGet(); - } - try { - completeBarrier.await(); - } catch (InterruptedException e) { - log.warn("Interrupted at waiting for the other threads to complete", e); - } catch (BrokenBarrierException e) { - log.warn("Complete barrier is broken", e); - } - FutureUtils.complete(doneFuture, null); - } - }); - } - doneFuture.join(); - assertEquals(1, numSuccesses.get()); - assertEquals(numBookies - 1, numFailures.get()); - } - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/HelpersTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/HelpersTest.java deleted file mode 100644 index f328149e9e8..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/HelpersTest.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd.helpers; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import io.etcd.jetcd.ByteSequence; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.commons.lang.RandomStringUtils; -import org.apache.commons.lang3.StringUtils; -import org.junit.Before; -import org.junit.Test; - -/** - * Integration test helpers. - */ -@Slf4j -public class HelpersTest extends EtcdTestBase { - - private static final Function BYTE_SEQUENCE_STRING_FUNCTION = - bs -> bs.toString(UTF_8); - - private static String getKey(String scope, int i) { - return String.format("%s-key-%010d", scope, i); - } - - private String scope; - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - scope = RandomStringUtils.randomAlphabetic(8); - } - - @Test - public void testEmptyKeyStream() throws Exception { - KeyStream ks = new KeyStream<>( - etcdClient.getKVClient(), - ByteSequence.from(getKey(scope, 0), UTF_8), - ByteSequence.from(getKey(scope, 100), UTF_8), - BYTE_SEQUENCE_STRING_FUNCTION - ); - List values = result(ks.readNext()); - assertTrue(values.isEmpty()); - - // read the values again - values = result(ks.readNext()); - assertTrue(values.isEmpty()); - } - - @Test - public void testKeyStreamBatch1() throws Exception { - testKeyStream(20, 1); - } - - @Test - public void testKeyStreamBatch2() throws Exception { - testKeyStream(20, 2); - } - - @Test - public void testKeyStreamBatch7() throws Exception { - testKeyStream(20, 7); - } - - @Test - public void testKeyStreamBatch10() throws Exception { - testKeyStream(20, 10); - } - - @Test - public void testKeyStreamBatch20() throws Exception { - testKeyStream(20, 20); - } - - @Test - public void testKeyStreamBatch40() throws Exception { - testKeyStream(20, 40); - } - - @Test - public void testKeyStreamBatchUnlimited() throws Exception { - testKeyStream(20, 0); - } - - private void testKeyStream(int numKeys, int batchSize) throws Exception { - for (int i = 0; i < numKeys; i++) { - String key = getKey(scope, i); - ByteSequence keyBs = ByteSequence.from(key.getBytes(UTF_8)); - result(etcdClient.getKVClient().put(keyBs, keyBs)); - } - - KeyStream ks = openKeyStream(batchSize); - AtomicInteger numReceived = new AtomicInteger(0); - while (true) { - List values = result(ks.readNext()); - log.info("Received values : {}", values); - if (values.isEmpty()) { - break; - } - for (int value : values) { - assertEquals(numReceived.getAndIncrement(), value); - } - } - assertEquals(numKeys, numReceived.get()); - } - - private void testKeyIterator(int numKeys, int batchSize) throws Exception { - for (int i = 0; i < numKeys; i++) { - String key = getKey(scope, i); - ByteSequence keyBs = ByteSequence.from(key, UTF_8); - result(etcdClient.getKVClient().put(keyBs, keyBs)); - } - - KeyStream ks = openKeyStream(batchSize); - KeyIterator ki = new KeyIterator<>(ks); - - AtomicInteger numReceived = new AtomicInteger(0); - while (ki.hasNext()) { - List values = ki.next(); - log.info("Received values : {}", values); - if (values.isEmpty()) { - break; - } - for (int value : values) { - assertEquals(numReceived.getAndIncrement(), value); - } - } - assertEquals(numKeys, numReceived.get()); - } - - @Test - public void testKeyIteratorBatch1() throws Exception { - testKeyIterator(20, 1); - } - - @Test - public void testKeyIteratorBatch2() throws Exception { - testKeyIterator(20, 2); - } - - @Test - public void testKeyIteratorBatch7() throws Exception { - testKeyIterator(20, 7); - } - - @Test - public void testKeyIteratorBatch10() throws Exception { - testKeyIterator(20, 10); - } - - @Test - public void testKeyIteratorBatch20() throws Exception { - testKeyIterator(20, 20); - } - - @Test - public void testKeyIteratorBatch40() throws Exception { - testKeyIterator(20, 40); - } - - @Test - public void testKeyIteratorBatchUnlimited() throws Exception { - testKeyIterator(20, 0); - } - - private KeyStream openKeyStream(int batchSize) { - KeyStream ks = new KeyStream<>( - etcdClient.getKVClient(), - ByteSequence.from(getKey(scope, 0).getBytes(UTF_8)), - ByteSequence.from(getKey(scope, Integer.MAX_VALUE).getBytes(UTF_8)), - bs -> { - String[] keyParts = StringUtils.split(bs.toString(UTF_8), '-'); - try { - return Integer.parseInt(keyParts[2]); - } catch (NumberFormatException nfe) { - log.error("Failed to parse key string '{}' : ", - bs.toString(UTF_8), nfe); - return -0xabcd; - } - }, - batchSize - ); - return ks; - } - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/KeySetReaderTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/KeySetReaderTest.java deleted file mode 100644 index d7a07fc2ff2..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/KeySetReaderTest.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd.helpers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import io.etcd.jetcd.ByteSequence; -import io.etcd.jetcd.options.PutOption; -import io.etcd.jetcd.support.CloseableClient; -import io.etcd.jetcd.support.Observers; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.function.Consumer; -import java.util.function.Function; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdTestBase; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version.Occurred; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.compress.utils.Sets; -import org.apache.commons.lang3.RandomStringUtils; -import org.junit.Test; - -/** - * Integration test {@link KeySetReader}. - */ -@Slf4j -public class KeySetReaderTest extends EtcdTestBase { - - private static final Function BYTE_SEQUENCE_STRING_FUNCTION = - bs -> bs.toString(StandardCharsets.UTF_8); - - @Test - public void testReadSingleKey() throws Exception { - String key = RandomStringUtils.randomAlphabetic(16); - ByteSequence keyBs = ByteSequence.from(key, StandardCharsets.UTF_8); - try (KeySetReader ksReader = new KeySetReader<>( - etcdClient, - BYTE_SEQUENCE_STRING_FUNCTION, - keyBs, - null - )) { - // key not exists - Versioned> versionedKeys = FutureUtils.result(ksReader.read()); - assertTrue( - "VersionedKeys : " + versionedKeys, - ((LongVersion) versionedKeys.getVersion()).getLongVersion() > 0L); - assertEquals(0, versionedKeys.getValue().size()); - assertFalse(ksReader.isWatcherSet()); - - // keys should be cached - assertEquals(versionedKeys, ksReader.getLocalValue()); - - // update a value - String value = RandomStringUtils.randomAlphabetic(32); - ByteSequence valueBs = ByteSequence.from(value, StandardCharsets.UTF_8); - FutureUtils.result(etcdClient.getKVClient().put(keyBs, valueBs)); - - // update the value should not change local value - assertEquals(versionedKeys, ksReader.getLocalValue()); - - // read the key again - Versioned> newVersionedKey = FutureUtils.result(ksReader.read()); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(1, newVersionedKey.getValue().size()); - assertEquals(Sets.newHashSet(key), newVersionedKey.getValue()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - } - } - - @Test - public void testWatchSingleKey() throws Exception { - String key = RandomStringUtils.randomAlphabetic(16); - ByteSequence keyBs = ByteSequence.from(key, StandardCharsets.UTF_8); - KeySetReader ksReader = null; - try { - ksReader = new KeySetReader<>( - etcdClient, - BYTE_SEQUENCE_STRING_FUNCTION, - keyBs, - null - ); - LinkedBlockingQueue>> notifications = new LinkedBlockingQueue<>(); - Consumer>> keyConsumer = consumeVersionedKeySet(notifications); - - // key not exists - Versioned> versionedKeys = FutureUtils.result(ksReader.readAndWatch(keyConsumer)); - assertTrue( - "VersionedKeys : " + versionedKeys, - ((LongVersion) versionedKeys.getVersion()).getLongVersion() > 0L); - assertEquals(0, versionedKeys.getValue().size()); - assertTrue(ksReader.isWatcherSet()); - - // keys should be cached - assertEquals(versionedKeys, ksReader.getLocalValue()); - Versioned> newVersionedKey = notifications.take(); - assertEquals(Occurred.CONCURRENTLY, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(versionedKeys, newVersionedKey); - versionedKeys = newVersionedKey; - - // update a value - String value = RandomStringUtils.randomAlphabetic(32); - ByteSequence valueBs = ByteSequence.from(value, StandardCharsets.UTF_8); - FutureUtils.result(etcdClient.getKVClient().put(keyBs, valueBs)); - - // we should get notified with updated key set - newVersionedKey = notifications.take(); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(1, newVersionedKey.getValue().size()); - assertEquals(Sets.newHashSet(key), newVersionedKey.getValue()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - versionedKeys = newVersionedKey; - - // delete the key - FutureUtils.result(etcdClient.getKVClient().delete(keyBs)); - newVersionedKey = notifications.take(); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(0, newVersionedKey.getValue().size()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - } finally { - if (null != ksReader) { - ksReader.close(); - } - } - assertNotNull(ksReader); - assertFalse(ksReader.isWatcherSet()); - } - - @Test - public void testWatchSingleKeyWithTTL() throws Exception { - String key = RandomStringUtils.randomAlphabetic(16); - ByteSequence keyBs = ByteSequence.from(key, StandardCharsets.UTF_8); - KeySetReader ksReader = null; - try { - ksReader = new KeySetReader<>( - etcdClient, - BYTE_SEQUENCE_STRING_FUNCTION, - keyBs, - null - ); - LinkedBlockingQueue>> notifications = new LinkedBlockingQueue<>(); - Consumer>> keyConsumer = consumeVersionedKeySet(notifications); - - // key not exists - Versioned> versionedKeys = FutureUtils.result(ksReader.readAndWatch(keyConsumer)); - assertTrue( - "VersionedKeys : " + versionedKeys, - ((LongVersion) versionedKeys.getVersion()).getLongVersion() > 0L); - assertEquals(0, versionedKeys.getValue().size()); - assertTrue(ksReader.isWatcherSet()); - - // keys should be cached - assertEquals(versionedKeys, ksReader.getLocalValue()); - // no watch event should be issued - Versioned> newVersionedKey = notifications.take(); - assertEquals(Occurred.CONCURRENTLY, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(versionedKeys, newVersionedKey); - versionedKeys = newVersionedKey; - - // create a key with ttl - long leaseId = FutureUtils.result(etcdClient.getLeaseClient().grant(1)).getID(); - String value = RandomStringUtils.randomAlphabetic(32); - ByteSequence valueBs = ByteSequence.from(value, StandardCharsets.UTF_8); - FutureUtils.result(etcdClient.getKVClient() - .put(keyBs, valueBs, PutOption.newBuilder().withLeaseId(leaseId).build())); - - // we should get notified with updated key set - newVersionedKey = notifications.take(); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(1, newVersionedKey.getValue().size()); - assertEquals(Sets.newHashSet(key), newVersionedKey.getValue()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - versionedKeys = newVersionedKey; - - // the key will be deleted after TTL - newVersionedKey = notifications.take(); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(0, newVersionedKey.getValue().size()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - } finally { - if (null != ksReader) { - ksReader.close(); - } - } - assertNotNull(ksReader); - assertFalse(ksReader.isWatcherSet()); - } - - @Test - public void testReadKeySet() throws Exception { - String prefix = RandomStringUtils.randomAlphabetic(16); - ByteSequence beginKeyBs = ByteSequence.from(prefix + "-000", StandardCharsets.UTF_8); - ByteSequence endKeyBs = ByteSequence.from(prefix + "-999", StandardCharsets.UTF_8); - try (KeySetReader ksReader = new KeySetReader<>( - etcdClient, - BYTE_SEQUENCE_STRING_FUNCTION, - beginKeyBs, - endKeyBs - )) { - // key not exists - Versioned> versionedKeys = FutureUtils.result(ksReader.read()); - assertTrue( - "VersionedKeys : " + versionedKeys, - ((LongVersion) versionedKeys.getVersion()).getLongVersion() > 0L); - assertEquals(0, versionedKeys.getValue().size()); - assertFalse(ksReader.isWatcherSet()); - - // keys should be cached - assertEquals(versionedKeys, ksReader.getLocalValue()); - - Set expectedKeySet = new HashSet<>(); - for (int i = 0; i < 20; i++) { - // update a value - String key = String.format("%s-%03d", prefix, i); - String value = RandomStringUtils.randomAlphabetic(32); - ByteSequence keyBs = ByteSequence.from(key, StandardCharsets.UTF_8); - ByteSequence valueBs = ByteSequence.from(value, StandardCharsets.UTF_8); - expectedKeySet.add(key); - FutureUtils.result(etcdClient.getKVClient().put(keyBs, valueBs)); - - // update the value should not change local value - assertEquals(versionedKeys, ksReader.getLocalValue()); - - // read the key again - Versioned> newVersionedKey = FutureUtils.result(ksReader.read()); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(expectedKeySet, newVersionedKey.getValue()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - versionedKeys = newVersionedKey; - } - } - } - - @Test - public void testWatchKeySet() throws Exception { - String prefix = RandomStringUtils.randomAlphabetic(16); - ByteSequence beginKeyBs = ByteSequence.from(prefix + "-000", StandardCharsets.UTF_8); - ByteSequence endKeyBs = ByteSequence.from(prefix + "-999", StandardCharsets.UTF_8); - KeySetReader ksReader = null; - try { - ksReader = new KeySetReader<>( - etcdClient, - BYTE_SEQUENCE_STRING_FUNCTION, - beginKeyBs, - endKeyBs - ); - LinkedBlockingQueue>> notifications = new LinkedBlockingQueue<>(); - Consumer>> keyConsumer = consumeVersionedKeySet(notifications); - - // key not exists - Versioned> versionedKeys = FutureUtils.result(ksReader.readAndWatch(keyConsumer)); - assertTrue( - "VersionedKeys : " + versionedKeys, - ((LongVersion) versionedKeys.getVersion()).getLongVersion() > 0L); - assertEquals(0, versionedKeys.getValue().size()); - assertTrue(ksReader.isWatcherSet()); - - // keys should be cached - assertEquals(versionedKeys, ksReader.getLocalValue()); - Versioned> newVersionedKey = notifications.take(); - assertEquals(Occurred.CONCURRENTLY, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(versionedKeys, newVersionedKey); - versionedKeys = newVersionedKey; - - Set expectedKeySet = new HashSet<>(); - for (int i = 0; i < 20; i++) { - // update a value - String key = String.format("%s-%03d", prefix, i); - String value = RandomStringUtils.randomAlphabetic(32); - ByteSequence keyBs = ByteSequence.from(key, StandardCharsets.UTF_8); - ByteSequence valueBs = ByteSequence.from(value, StandardCharsets.UTF_8); - expectedKeySet.add(key); - FutureUtils.result(etcdClient.getKVClient().put(keyBs, valueBs)); - - // we should get notified with updated key set - newVersionedKey = notifications.take(); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(expectedKeySet, newVersionedKey.getValue()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - versionedKeys = newVersionedKey; - } - - for (int i = 0; i < 20; i++) { - // delete the key - String key = String.format("%s-%03d", prefix, i); - ByteSequence keyBs = ByteSequence.from(key, StandardCharsets.UTF_8); - expectedKeySet.remove(key); - FutureUtils.result(etcdClient.getKVClient().delete(keyBs)); - - // we should get notified with updated key set - newVersionedKey = notifications.take(); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(expectedKeySet, newVersionedKey.getValue()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - versionedKeys = newVersionedKey; - } - } finally { - if (null != ksReader) { - ksReader.close(); - } - } - assertNotNull(ksReader); - assertFalse(ksReader.isWatcherSet()); - } - - @Test - public void testWatchKeySetWithTTL() throws Exception { - String prefix = RandomStringUtils.randomAlphabetic(16); - ByteSequence beginKeyBs = ByteSequence.from(prefix + "-000", StandardCharsets.UTF_8); - ByteSequence endKeyBs = ByteSequence.from(prefix + "-999", StandardCharsets.UTF_8); - KeySetReader ksReader = null; - try { - ksReader = new KeySetReader<>( - etcdClient, - BYTE_SEQUENCE_STRING_FUNCTION, - beginKeyBs, - endKeyBs - ); - LinkedBlockingQueue>> notifications = new LinkedBlockingQueue<>(); - Consumer>> keyConsumer = consumeVersionedKeySet(notifications); - - // key not exists - Versioned> versionedKeys = FutureUtils.result(ksReader.readAndWatch(keyConsumer)); - assertTrue( - "VersionedKeys : " + versionedKeys, - ((LongVersion) versionedKeys.getVersion()).getLongVersion() > 0L); - assertEquals(0, versionedKeys.getValue().size()); - assertTrue(ksReader.isWatcherSet()); - - // keys should be cached - assertEquals(versionedKeys, ksReader.getLocalValue()); - // no watch event should be issued - Versioned> newVersionedKey = notifications.take(); - assertEquals(Occurred.CONCURRENTLY, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(versionedKeys, newVersionedKey); - versionedKeys = newVersionedKey; - - // create keys with ttl - long leaseId = FutureUtils.result(etcdClient.getLeaseClient().grant(1)).getID(); - CloseableClient ka = etcdClient.getLeaseClient().keepAlive(leaseId, Observers.observer(response -> { - })); - - Set expectedKeySet = new HashSet<>(); - for (int i = 0; i < 20; i++) { - String key = String.format("%s-%03d", prefix, i); - String value = RandomStringUtils.randomAlphabetic(32); - ByteSequence keyBs = ByteSequence.from(key, StandardCharsets.UTF_8); - ByteSequence valueBs = ByteSequence.from(value, StandardCharsets.UTF_8); - expectedKeySet.add(key); - FutureUtils.result(etcdClient.getKVClient() - .put(keyBs, valueBs, PutOption.newBuilder().withLeaseId(leaseId).build())); - - // we should get notified with updated key set - newVersionedKey = notifications.take(); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertEquals(expectedKeySet, newVersionedKey.getValue()); - - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - versionedKeys = newVersionedKey; - } - - // stop keep alive all the keys should be expired. - ka.close(); - - // all the keys will be deleted after TTL in same batch. - newVersionedKey = notifications.take(); - // local value should be changed - assertEquals(newVersionedKey, ksReader.getLocalValue()); - assertEquals(Occurred.AFTER, newVersionedKey.getVersion().compare(versionedKeys.getVersion())); - assertTrue(newVersionedKey.getValue().isEmpty()); - } finally { - if (null != ksReader) { - ksReader.close(); - } - } - assertNotNull(ksReader); - assertFalse(ksReader.isWatcherSet()); - } -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/integration/SmokeTest.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/integration/SmokeTest.java deleted file mode 100644 index c29ad426628..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/integration/SmokeTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.metadata.etcd.integration; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; - -import java.util.concurrent.atomic.AtomicInteger; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.api.BookKeeper; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteAdvHandle; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.metadata.etcd.testing.EtcdBKClusterTestBase; -import org.junit.Test; - -/** - * Smoke testing etcd metadata drives. - */ -@Slf4j -public class SmokeTest extends EtcdBKClusterTestBase { - - private static final byte[] PASSWD = "smoketest".getBytes(UTF_8); - - private static void readEntries(BookKeeper bk, - long ledgerId, - int numExpectedEntries) throws Exception { - try (ReadHandle readlh = result(bk.newOpenLedgerOp() - .withLedgerId(ledgerId) - .withDigestType(DigestType.CRC32C) - .withPassword(PASSWD) - .execute() - )) { - long lac = readlh.getLastAddConfirmed(); - AtomicInteger idx = new AtomicInteger(0); - try (LedgerEntries entries = readlh.read(0, lac)) { - entries.forEach(e -> assertEquals( - String.format("entry-%03d", idx.getAndIncrement()), - new String(e.getEntryBytes(), UTF_8))); - } - assertEquals(idx.get(), numExpectedEntries); - } - } - - @Test - public void testReadWrite() throws Exception { - int numEntries = 100; - try (BookKeeper bk = BookKeeper.newBuilder(conf).build()) { - long ledgerId; - try (WriteHandle wh = result(bk.newCreateLedgerOp() - .withDigestType(DigestType.CRC32C) - .withPassword(PASSWD) - .execute())) { - ledgerId = wh.getId(); - log.info("Successfully created ledger {} to append entries.", ledgerId); - for (int i = 0; i < numEntries; i++) { - wh.append(String.format("entry-%03d", i).getBytes(UTF_8)); - } - } - log.info("Opening ledger {} to read entries ...", ledgerId); - readEntries(bk, ledgerId, numEntries); - log.info("Successfully read {} entries from ledger {}", numEntries, ledgerId); - } - } - - @Test - public void testReadWriteAdv() throws Exception { - final int numEntries = 100; - try (BookKeeper bk = BookKeeper.newBuilder(conf).build()) { - long ledgerId; - try (WriteAdvHandle wah = result(bk.newCreateLedgerOp() - .withDigestType(DigestType.CRC32C) - .withPassword(PASSWD) - .makeAdv() - .execute())) { - ledgerId = wah.getId(); - log.info("Successfully created adv ledger {} to append entries.", ledgerId); - for (int i = 0; i < numEntries; i++) { - wah.write(i, String.format("entry-%03d", i).getBytes(UTF_8)); - } - } - log.info("Opening adv ledger {} to read entries ...", ledgerId); - readEntries(bk, ledgerId, numEntries); - log.info("Successfully read {} entries from adv ledger {}", numEntries, ledgerId); - } - } - - - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdBKClusterTestBase.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdBKClusterTestBase.java deleted file mode 100644 index c7e81f4d7e3..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdBKClusterTestBase.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.metadata.etcd.testing; - -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.bookie.Bookie; -import org.apache.bookkeeper.bookie.MockUncleanShutdownDetection; -import org.apache.bookkeeper.bookie.TestBookieImpl; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.api.BookKeeper; -import org.apache.bookkeeper.common.net.ServiceURI; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.conf.TestBKConfiguration; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.metadata.etcd.EtcdMetadataBookieDriver; -import org.apache.bookkeeper.metadata.etcd.EtcdMetadataClientDriver; -import org.apache.bookkeeper.proto.BookieServer; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.bookkeeper.util.PortManager; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; - -/** - * A test base that run an Etcd based bookkeeper cluster. - */ -@Slf4j -public abstract class EtcdBKClusterTestBase extends EtcdTestBase { - - protected static ClientConfiguration baseClientConf; - protected static ServerConfiguration baseServerConf; - protected static final int NUM_BOOKIES = 3; - protected static final List BOOKIES = new ArrayList<>(NUM_BOOKIES); - protected static final List TMP_DIRS = new ArrayList<>(NUM_BOOKIES); - - protected static File createTempDir(String prefix, String suffix) throws IOException { - File dir = IOUtils.createTempDir(prefix, suffix); - TMP_DIRS.add(dir); - return dir; - } - - protected static ServerConfiguration newServerConfiguration() throws Exception { - File f = createTempDir("bookie", "test"); - int port = PortManager.nextFreePort(); - return newServerConfiguration(port, f, new File[] { f }); - } - - protected static ServerConfiguration newServerConfiguration(int port, File journalDir, File[] ledgerDirs) { - ServerConfiguration conf = new ServerConfiguration(baseServerConf); - conf.setBookiePort(port); - conf.setJournalDirName(journalDir.getPath()); - String[] ledgerDirNames = new String[ledgerDirs.length]; - for (int i = 0; i < ledgerDirs.length; i++) { - ledgerDirNames[i] = ledgerDirs[i].getPath(); - } - conf.setLedgerDirNames(ledgerDirNames); - conf.setEnableTaskExecutionStats(true); - return conf; - } - - @BeforeClass - public static void setupCluster() throws Exception { - setupCluster(NUM_BOOKIES); - } - protected static void setupCluster(int numBookies) throws Exception { - EtcdTestBase.setupCluster(); - - MetadataDrivers.registerBookieDriver( - "etcd", EtcdMetadataBookieDriver.class - ); - MetadataDrivers.registerClientDriver( - "etcd", EtcdMetadataClientDriver.class - ); - - log.info("Successfully started etcd at:" - + " internal service uri = {}, external service uri = {}", - etcdContainer.getInternalServiceUri(), etcdContainer.getExternalServiceUri()); - - ServiceURI uri = ServiceURI.create(etcdContainer.getExternalServiceUri()); - - baseClientConf = new ClientConfiguration() - .setMetadataServiceUri(uri.getUri().toString()); - baseServerConf = TestBKConfiguration.newServerConfiguration() - .setMetadataServiceUri(uri.getUri().toString()); - // format the cluster - assertTrue(BookKeeperAdmin.format(baseServerConf, false, true)); - // start bookies - startNumBookies(numBookies); - } - - private static void startNumBookies(int numBookies) throws Exception { - for (int i = 0; i < numBookies; i++) { - ServerConfiguration conf = newServerConfiguration(); - log.info("Starting new bookie on port : {}", conf.getBookiePort()); - BookieServer server = startBookie(conf); - synchronized (BOOKIES) { - BOOKIES.add(server); - } - } - } - private static BookieServer startBookie(ServerConfiguration conf) throws Exception { - conf.setAutoRecoveryDaemonEnabled(true); - TestStatsProvider provider = new TestStatsProvider(); - Bookie bookie = new TestBookieImpl(conf); - BookieServer server = new BookieServer(conf, bookie, provider.getStatsLogger(""), - ByteBufAllocator.DEFAULT, - new MockUncleanShutdownDetection()); - server.start(); - return server; - } - - @AfterClass - public static void teardownCluster() throws Exception { - // stop bookies - stopBookies(); - // stop metadata store - EtcdTestBase.teardownCluster(); - log.info("Stopped the metadata store."); - // clean up temp dirs - for (File f : TMP_DIRS) { - FileUtils.deleteDirectory(f); - } - log.info("Clean up all the temp directories."); - } - - private static void stopBookies() { - synchronized (BOOKIES) { - BOOKIES.forEach(BookieServer::shutdown); - log.info("Stopped all the bookies."); - } - } - - protected ClientConfiguration conf; - protected BookKeeper bk; - - @Before - public void setUp() throws Exception { - conf = new ClientConfiguration() - .setMetadataServiceUri(etcdContainer.getExternalServiceUri()); - bk = BookKeeper.newBuilder(conf).build(); - } - - @After - public void tearDown() throws Exception { - if (null != bk) { - bk.close(); - } - } - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdContainer.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdContainer.java deleted file mode 100644 index 0178e4d2ab5..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdContainer.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd.testing; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.async.ResultCallback; -import com.github.dockerjava.api.command.LogContainerCmd; -import com.github.dockerjava.api.model.Frame; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import lombok.extern.slf4j.Slf4j; -import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.ContainerLaunchException; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.WaitingConsumer; -import org.testcontainers.containers.wait.strategy.WaitStrategy; -import org.testcontainers.utility.LogUtils; - -/** - * Etcd test container. - */ -@Slf4j -public class EtcdContainer extends GenericContainer { - - static class LogContainerResultCb extends ResultCallback.Adapter { - @Override - public void onNext(Frame frame) { - log.info(new String(frame.getPayload(), UTF_8)); - } - } - - public static final String NAME = "etcd"; - public static final int CLIENT_PORT = 2379; - - private final String clusterName; - - public EtcdContainer(String clusterName) { - super("quay.io/coreos/etcd:v3.3"); - this.clusterName = clusterName; - } - - public String getExternalServiceUri() { - return "etcd://" + getHost() + ":" + getEtcdClientPort() + "/clusters/" + clusterName; - } - - public String getInternalServiceUri() { - return "etcd://" + NAME + ":" + CLIENT_PORT + "/clusters/" + clusterName; - } - - @Override - protected void configure() { - super.configure(); - - String[] command = new String[] { - "/usr/local/bin/etcd", - "--name", NAME + "0", - "--initial-advertise-peer-urls", "http://" + NAME + ":2380", - "--listen-peer-urls", "http://0.0.0.0:2380", - "--advertise-client-urls", "http://" + NAME + ":2379", - "--listen-client-urls", "http://0.0.0.0:2379", - "--initial-cluster", NAME + "0=http://" + NAME + ":2380" - }; - - this.withNetworkAliases(NAME) - .withExposedPorts(CLIENT_PORT) - .withCreateContainerCmdModifier(createContainerCmd -> { - createContainerCmd.withHostName(NAME); - createContainerCmd.withName(clusterName + "-" + NAME); - }) - .withCommand(command) - .withNetworkAliases(NAME) - .waitingFor(waitStrategy()); - tailContainerLog(); - } - - public void tailContainerLog() { - CompletableFuture.runAsync(() -> { - while (null == this.getContainerId()) { - try { - TimeUnit.MILLISECONDS.sleep(100); - } catch (InterruptedException e) { - return; - } - } - - LogContainerCmd logContainerCmd = this.dockerClient.logContainerCmd(this.getContainerId()); - logContainerCmd.withStdOut(true).withStdErr(true).withFollowStream(true); - logContainerCmd.exec(new LogContainerResultCb()); - }); - } - - public int getEtcdClientPort() { - return getMappedPort(CLIENT_PORT); - } - - public String getClientEndpoint() { - return String.format("http://%s:%d", getHost(), getEtcdClientPort()); - } - - private WaitStrategy waitStrategy() { - return new org.testcontainers.containers.wait.strategy.AbstractWaitStrategy() { - @Override - protected void waitUntilReady() { - final DockerClient client = DockerClientFactory.instance().client(); - final WaitingConsumer waitingConsumer = new WaitingConsumer(); - - LogUtils.followOutput(client, waitStrategyTarget.getContainerId(), waitingConsumer); - - try { - waitingConsumer.waitUntil( - f -> f.getUtf8String().contains("ready to serve client requests"), - startupTimeout.getSeconds(), - TimeUnit.SECONDS, - 1 - ); - } catch (TimeoutException e) { - throw new ContainerLaunchException("Timed out"); - } - } - }; - } - - -} diff --git a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdTestBase.java b/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdTestBase.java deleted file mode 100644 index 00758420057..00000000000 --- a/metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdTestBase.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.metadata.etcd.testing; - -import io.etcd.jetcd.Client; -import java.util.Set; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.function.Consumer; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.commons.lang.RandomStringUtils; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.rules.Timeout; - -/** - * A test base that setup etcd cluster for testing. - */ -@Slf4j -public abstract class EtcdTestBase { - - @Rule - public Timeout globalTimeout = Timeout.seconds(120); - - protected static EtcdContainer etcdContainer; - - @BeforeClass - public static void setupCluster() throws Exception { - etcdContainer = new EtcdContainer(RandomStringUtils.randomAlphabetic(8)); - etcdContainer.start(); - log.info("Successfully started etcd at {}", etcdContainer.getClientEndpoint()); - } - - @AfterClass - public static void teardownCluster() throws Exception { - if (null != etcdContainer) { - etcdContainer.stop(); - log.info("Successfully stopped etcd."); - } - } - - protected Client etcdClient; - - protected static Client newEtcdClient() { - Client client = Client.builder() - .endpoints(etcdContainer.getClientEndpoint()) - .build(); - return client; - } - - protected static Consumer>> consumeVersionedKeySet( - LinkedBlockingQueue>> notifications) { - return versionedKeys -> { - log.info("Received new keyset : {}", versionedKeys); - try { - notifications.put(versionedKeys); - } catch (InterruptedException e) { - log.error("Interrupted at enqueuing updated key set", e); - } - }; - } - - @Before - public void setUp() throws Exception { - etcdClient = newEtcdClient(); - log.info("Successfully build etcd client to endpoint {}", etcdContainer.getClientEndpoint()); - } - - @After - public void tearDown() throws Exception { - if (null != etcdClient) { - etcdClient.close(); - log.info("Successfully close etcd client to endpoint {}", etcdContainer.getClientEndpoint()); - } - } - -} diff --git a/my-documentation/removed_test_files.txt b/my-documentation/removed_test_files.txt new file mode 100644 index 00000000000..01776998f26 --- /dev/null +++ b/my-documentation/removed_test_files.txt @@ -0,0 +1,672 @@ +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/integration/SmokeTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/HelpersTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/helpers/KeySetReaderTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdContainer.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdBKClusterTestBase.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/testing/EtcdTestBase.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdCookieTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdRegistrationTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdClusterTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLayoutManagerTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/Etcd64bitIdGeneratorTest.java +./metadata-drivers/etcd/src/test/java/org/apache/bookkeeper/metadata/etcd/EtcdLedgerManagerTest.java +./stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/CodahaleOpStatsTest.java +./stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/FastTimerTest.java +./stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusFormatter.java +./stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestBookieAuthZFactory.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/net/NetworkTopologyImplTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/net/ResolvedBookieSocketAddressTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/net/BookieIdTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/verifier/BookkeeperVerifierTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/NetworkLessBookieTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockLedgerData.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ForceLedgerProcessorV3Test.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/checksum/CompositeByteBufUnwrapBugReproduceTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClient.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorV3Test.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookieClient.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/LongPollReadEntryProcessorV3Test.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBKStats.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/ReadEntryProcessorTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBackwardCompatCMS42.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/WriteEntryProcessorTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/MockBookies.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BatchedReadEntryProcessorTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBookieRequestProcessor.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieBackpressureForV2Test.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/GetBookieInfoProcessorV3Test.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/TriggerGCServiceTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/ListLedgerServiceTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/MetricsServiceTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/service/AutoRecoveryStatusServiceTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/component/TestServerLifecycleComponent.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestBookieBoot.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestEmbeddedServer.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/SystemPropertiesConfigurationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/NoSystemPropertiesConfigurationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestServerConfiguration.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/TestBKConfiguration.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/conf/AbstractConfigurationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieAutoRecoveryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicBookieCheckTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTaskTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AutoRecoveryMainTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorCheckAllLedgersTaskTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/BookieLedgerIndexTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorRollingRestartTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuthAutoRecoveryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorLedgerCheckerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTaskTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorBookieCheckTaskTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestAutoRecoveryAlongWithBookieServers.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestLedgerUnderreplicationManager.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/TestReplicationWorker.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/ReplicationTestUtil.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationManager.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationClient.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithBookieAddressTracking.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/BookieServiceInfoTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/TestZkRegistrationClientWithoutBookieAddressTracking.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/MockRegistrationManager.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/discover/AbstractTestZkRegistrationClient.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/ByteBufListTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/NettyChannelUtilTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashSetTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/SynchronizedHashMultiMapTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashMapTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongPairHashMapTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentOpenHashSetTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongHashMapTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/collections/ConcurrentLongLongHashMapTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestUtils.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/IteratorUtilityTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/StaticDNSResolver.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedgerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestHardLink.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/SubTreeCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZeroBuffer.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestZkUtils.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/LoggerOutput.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/util/TestDiskChecker.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/versioning/TestLongVersion.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestRetryPolicy.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientBoundExpBackoffRP.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZooKeeperClient.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/TestZKClientExpBackoffWithDeadlineRP.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/zookeeper/MockZooKeeperTestCase.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/auth/TestAuth.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreTableAsyncToSyncConverter.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/TestMetaStore.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/metastore/MetastoreScannableTableAsyncToSyncConverter.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadEntryListener.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeBatchRead.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientZKSessionExpiry.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPiggybackLAC.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplicationWithMock.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockClientContext.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSpeculativeRead.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeper.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockReadHandle.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerChecker.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BKExceptionTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestGetBookieInfoTimeout.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperClientTestsWithBookieErrors.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntryImplTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/impl/LedgerEntriesImplTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ListLedgersTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/DeferredSyncTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedOpTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/RoundRobinDistributionScheduleTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCloseTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRegionAwareEnsemblePlacementPolicy.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ClientUtil.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicy.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/ExplicitLACWithWriteHandleAPITest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperApiTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteAdvHandleTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BKExceptionTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersOpenLedgerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/LedgerMetadataTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteHandleTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/BookKeeperBuildersTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/WriteFlagTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockBookKeeperTestCase.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxEnsembleChangeNum.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedLongPoll.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MetadataUpdateLoopTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestLedgerFragmentReplication.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecovery2Test.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawarePolicyNotificationUpdates.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerHandle.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerOpTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestZoneawareEnsemblePlacementPolicy.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/PendingAddOpTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ParallelLedgerRecoveryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWeightedRandomSelection.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastEntry.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ExplicitLacTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MdcContextTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestPendingReadLacOp.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/SlowBookieTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestParallelRead.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadTimeout.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/MockLedgerEntry.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieHealthCheck.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRackawareEnsemblePlacementPolicyUsingScript.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestMaxSizeWorkersQueue.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ConcurrentV2RecoveryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryUseIOThreadTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestReadLastConfirmedAndEntry.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerClose2Test.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerHandleAdapter.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBookieWatcher.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperCloseTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestAddEntryQuorumTimeout.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/HandleFailuresTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieAddressResolverDisabledTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestTryReadLastConfirmed.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTestClient.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/UpdateLedgerCmdTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestFencing.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestWatchEnsembleChange.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestBatchedRead.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerRecoveryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerCmdTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDisableEnsembleChange.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieNetworkAddressChangeTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/ReadLastConfirmedAndEntryOpTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieWriteLedgersWithDifferentDigestsTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/client/GenericEnsemblePlacementPolicyTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLongZkLedgerIdGenerator.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MockLedgerManager.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerMetadataCreationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerIteratorTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/AbstractZkLedgerManagerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/ZkLedgerLayoutTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/LedgerManagerTestCase.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerMetadataSerDe.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLayoutManager.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestZkLedgerIdGenerator.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataBookieDriverTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriverTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBaseStaticTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/MetadataDriversTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerLayout.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/TestLedgerManager.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/CleanupLedgerManagerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConcurrentLedgerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerCreateDeleteTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperCluster.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/OpStatTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConfigurationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/AsyncLedgerOpsTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/MultipleThreadReadTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TmpDirs.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LocalBookiesRegistryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ConditionalSetTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/LedgerDeleteTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ForceReadOnlyBookieTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/TestCallbacks.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieFailureTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieReadWriteTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperUtil.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ZooKeeperClusterUtil.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/CloseTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookKeeperClusterTestCase.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieJournalRollingWithReuseJournalTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieZKExpireTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MiniKdc.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/GSSAPIBookKeeperTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/sasl/MD5DigestBookKeeperTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieAccessor.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/FileInfoBackingCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerDirsManagerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LastAddConfirmedUpdateNotificationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalBypassTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStickyReadsTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SkipListArenaTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalMaxMemoryTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpgradeTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTestBase.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithoutMetadataCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UpdateCookieCmdTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalPageCacheFlushTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieIndexDirTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexPersistenceMgrTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CookieTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/EntryLogTestUtils.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/MockEntryLogIds.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LocationsIndexRebuildTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbReadLedgerIndexEntriesTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexCheckOpTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildOpTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWriteCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageIndexDirTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ArraySortGroupTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ConversionRollbackTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/WriteCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageWithDirectEntryLoggerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageBookieTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/EntryLocationIndexTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/ReadCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorageReadCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/LedgersIndexRebuildTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/PersistentEntryLogMetadataMapTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestTransactionalEntryLogCompactor.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestBuffer.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestEntryLogIds.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLogger.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestMetadata.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectReader.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectEntryLoggerCompat.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/directentrylogger/TestDirectWriter.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieWriteToJournalTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ClusterInfoCommandTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SingleBookieInitializationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieDeferredSyncTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EntryMemTableTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ForceAuditorChecksCmdTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/TestBookieImpl.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithoutMetadataCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowSortedLedgerStorage.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieImplTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SlowInterleavedLedgerStorage.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/AdvertisedAddressTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockUncleanShutdownDetection.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BufferedChannelTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieInitializationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByBytesWithMetadataCacheTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/UncleanShutdownDetectionTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GcOverreplicatedLedgerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/GarbageCollectorThreadTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SyncThreadTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageCheckpointTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalForceTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CheckpointOnNewLedgersTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieStorageThresholdTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/IndexCorruptionTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieJournalNoSyncTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/StateManagerTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/DefaultEntryLogTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/LedgerStorageTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/EnableZkSecurityBasicTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/SortedLedgerStorageCheckpointTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorageTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/CookieValidationTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityServiceTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/DataIntegrityCheckTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/WriteSetsTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/EntryCopierTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MetadataAsyncIteratorTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/datainteg/MockDataIntegrityCheck.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieMultipleJournalsTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieThreadTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShutdownTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CreateNewLogTest.java +./bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/CompactionByEntriesWithMetadataCacheTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/CommonHashesTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCProvidersTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/crc/CRCTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalLongHashTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessIntHashTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractIncrementalIntHashTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatefulHashTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/impl/AbstractStatelessLongHashTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/checksum/Java9IntHashTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/checksum/ChecksumTest.java +./circe-checksum/src/test/java/com/scurrilous/circe/utils/NativeUtilsTests.java +./bookkeeper-common-allocator/src/test/java/org/apache/bookkeeper/common/allocator/impl/ByteBufAllocatorBuilderTest.java +./bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/JettyHttpServer.java +./bookkeeper-http/servlet-http-server/src/test/java/org/apache/bookkeeper/http/servlet/TestBookieHttpServiceServlet.java +./bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpServer.java +./bookkeeper-http/vertx-http-server/src/test/java/org/apache/bookkeeper/http/vertx/TestVertxHttpsServer.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestComponentStarter.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/component/TestLifecycleComponentStack.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigDefTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/RangeValidatorTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/validators/ClassValidatorTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyGroupTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/conf/ConfigKeyTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BlockingMpscQueueTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/GrowableArrayBlockingQueueTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/BatchedArrayBlockingQueueTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/collections/RecyclableArrayListTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TimedOutTestsListener.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/TestTimedOutTestsListener.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/util/package-info.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorControllerTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockExecutorController.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClockTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/executors/MockClock.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/MoreAsserts.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/annotations/FlakyTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/concurrent/TestFutureUtils.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestReflectionUtils.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MockTicker.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestBackoff.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSingleThreadExecutor.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestSharedResourceManager.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestThreadSelection.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/MemoryLimitControllerTest.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestWatchable.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestMathUtils.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/common/util/TestOrderedExecutorDecorators.java +./bookkeeper-common/src/test/java/org/apache/bookkeeper/test/TestStatsProvider.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestStateStore.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStore.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStoreCheckpoint.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStoreWithCheckpoints.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestKVUtils.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStore.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCUtils.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCStoreImpl.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCAsyncBytesStoreImpl.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/op/proto/ProtoCompareImplTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/dlog/DLCheckpointStoreTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/RocksCheckpointerTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/fs/FSCheckpointManagerTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/RocksUtilsTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerWithSchedulerTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorController.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClockTest.java +./stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClock.java +./stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/TestStreamRange.java +./stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java +./stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java +./stream/server/src/test/java/org/apache/bookkeeper/stream/server/TestStorageServerMain.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/DirectPingPongServiceTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/ProxyPingPongServiceTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/GrpcStatsIntegrationTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ClientStatsTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ServerStatsTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityBinaryMarshallerTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityInputStreamMarshallerTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/LongBinaryMarshallerTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/util/TestBytes.java +./stream/common/src/test/java/org/apache/bookkeeper/common/util/TestVarInt.java +./stream/common/src/test/java/org/apache/bookkeeper/common/util/TestExceptionUtils.java +./stream/common/src/test/java/org/apache/bookkeeper/common/router/HashRouterTest.java +./stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java +./stream/common/src/test/java/org/apache/bookkeeper/common/coder/CoderBasicTestCase.java +./stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestStringUtf8Coder.java +./stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestByteArrayCoder.java +./stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestVarIntCoder.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/ByteBufTableImplTest.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestPByteBufTableImpl.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java +./stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java +./stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/admin/TestStorageAdminClientImpl.java +./stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java +./stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/StorageClientImplTest.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerManager.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerInfo.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannelManager.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStreamMetadataCache.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestStreamRanges.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestHashStreamRanges.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplWithRetriesTest.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteStreamRpc.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateStreamRpc.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteNamespaceRpc.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStorageServerClientManagerImpl.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamRpc.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestProtocolInternalUtils.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamByIdRpc.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannel.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannelManager.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/RpcUtilsTest.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/TestNetUtils.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/ListenableFutureRpcProcessorTest.java +./stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/GrpcChannelsTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestStorageContainerStoreBuilder.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerPlacementPolicyImpl.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerControllerTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreCacheTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtilsTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RoutingHeaderProxyInterceptorTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RangeRoutingTableImplTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/StorageContainerProxyChannelManagerImplTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorListenerTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterMetadataStoreTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerImplTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerLeaderImplTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/InMemClusterMetadataStoreTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCStoreFactoryImplTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCAsyncStoreTestBase.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestResponseObserver.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/stream/TestMetaRangeImpl.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java +./stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java +./stream/storage/api/src/test/java/org/apache/bookkeeper/stream/storage/conf/TestStorageConfiguration.java +./stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/GrpcChannelsTest.java +./stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/BKRegistrationNameResolverTest.java +./stream/tests-common/target/generated-sources/protobuf/java/org/apache/bookkeeper/stream/coder/protobuf/test/Proto2CoderTestMessages.java +./stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestLogRecordSet.java +./stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestDLSN.java +./stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConfigurationSubscription.java +./stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConcurrentBaseConfiguration.java +./stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/PropertiesWriter.java +./stream/distributedlog/common/src/test/java/org/apache/distributedlog/io/TestCompressionCodec.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTruncate.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClientBuilder.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogConfiguration.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestInterleavedReaders.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestConfigurationFeatureProvider.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControlManager.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControl.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentCreation.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKSyncLogReader.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogWriteHandler.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestNetUtils.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestDNSResolver.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClientUtils.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTxnId.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKNamespaceWatcher.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentFilters.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogMetadataStore.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStoreUtils.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStore.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZkMetadataResolver.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/logsegment/TestBKLogSegmentEntryReader.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentMetadataStore.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/federated/TestFederatedZKLogMetadataStore.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReadsMultiReader.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadUtils.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogManager.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDLMTestUtil.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocatorPool.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamReader.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/limiter/TestRequestLimiter.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestDistributedLock.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestZKSessionLock.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderLock.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntryPosition.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogReadHandler.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDLCK.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestPermitManager.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestDLUtils.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestUtils.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestConfUtils.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestTimeSequencer.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReader.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/selector/TestLogRecordSelectors.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogSegmentMetadataStoreUpdater.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogMetadata.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestDLMetadata.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogNamespace.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamWriter.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncBulkWrite.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/DLMTestUtil.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKWatcherManager.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKVersionedSetOp.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKTransaction.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogBase.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestWriteLimiter.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogSegmentWriter.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestCancelledRead.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentsZK.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClusterTestCase.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadAheadEntryReader.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestPerStreamLogSegmentCache.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestRollingPolicy.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntry.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/NonBlockingReadsTestUtil.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentMetadata.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/tools/TestDistributedLogTool.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicConfigurationFactory.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicDistributedLogConfiguration.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/PropertiesWriter.java +./stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestSequenceID.java +./stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFSBase.java +./stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFileSystem.java +./bookkeeper-slogger/slf4j/src/test/java/org/apache/bookkeeper/slogger/slf4j/Slf4jTest.java +./bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/MockSlogger.java +./bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/SloggerTest.java +./bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConsoleSloggerTest.java +./bookkeeper-slogger/api/src/test/java/org/apache/bookkeeper/slogger/ConcurrencyTest.java +./cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/CpuInfoTest.java +./cpu-affinity/src/test/java/org/apache/bookkeeper/common/util/affinity/impl/IsolatedProcessorsTest.java +./tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/commands/TestCommand.java +./tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/TestCli.java +./tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/CliTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTestBase.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieCommandTestBase.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CommandTestBase.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/MockCommandSupport.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTestBase.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieShellCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CookieCommandTestBase.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/LostBookieRecoveryDelayCommandTets.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/AutoRecoveryCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/QueryAutoRecoveryStatusCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/ListUnderReplicatedCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/WhoIsAuditorCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/TriggerAuditCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InfoCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/DecommissionCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/MetaFormatCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InitCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InstanceIdCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/RecoverCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/NukeExistingClusterCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/ListBookiesCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/health/SwitchOfHealthCheckCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/DeleteLedgerCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/SimpleTestCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/LedgerMetaDataCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GetCookieCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/DeleteCookieCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/CreateCookieCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandIndexTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/UpdateCookieCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LastMarkCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToInterleavedStorageCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToDBStorageCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LocalConsistencyCheckCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListFilesOnDiscCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListLedgersCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RegenerateInterleavedStorageIndexFileCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LedgerCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogMetadataCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/InitCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FlipBookieIdCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RebuildDBLedgerLocationsIndexCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FormatCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/SanityTestCommandTest.java +./tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java +./bookkeeper-benchmark/src/test/java/org/apache/bookkeeper/benchmark/TestBenchmark.java +./tests/integration/standalone/src/test/java/org/apache/bookkeeper/tests/integration/standalone/StandaloneTest.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/SimpleClusterTest.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/BookKeeperClusterTestBase.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/BkCtlTest.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/LocationClientTest.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKClusterSpec.java +./tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKCluster.java +./tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/BookieShellTestBase.java +./tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestBookieShellCluster.java +./tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestCLI.java +./tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestSmoke.java +./tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestDlogCLI.java +./tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/integration/utils/MavenClassLoaderTest.java +./tests/shaded/bookkeeper-server-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerShadedJarTest.java +./tests/shaded/bookkeeper-server-tests-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerTestsShadedJarTest.java +./tests/shaded/distributedlog-core-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/DistributedLogCoreShadedJarTest.java +./tests/backward-compat/bc-non-fips/src/test/java/org/apache/bookkeeper/tls/TestBCNonFips.java diff --git a/my-documentation/remover_test_files.sh b/my-documentation/remover_test_files.sh new file mode 100644 index 00000000000..6ecdbe6dbf1 --- /dev/null +++ b/my-documentation/remover_test_files.sh @@ -0,0 +1,3 @@ +find . -type f -wholename "*/test/*.java" >> my-documentation/removed_test_files.txt +find . -type f -wholename "*/test/*.java" -exec git rm {} \; + diff --git a/stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/CodahaleOpStatsTest.java b/stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/CodahaleOpStatsTest.java deleted file mode 100644 index ad4e7de023c..00000000000 --- a/stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/CodahaleOpStatsTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * 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. - */ -package org.apache.bookkeeper.stats.codahale; - -import static org.junit.Assert.assertEquals; - -import org.apache.bookkeeper.stats.OpStatsData; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.junit.Test; - -/** - * Unit test of {@link CodahaleOpStatsLogger}. - */ - -public class CodahaleOpStatsTest { - @Test - public void testToOpStatsData() { - OpStatsLogger logger = new CodahaleMetricsProvider().getStatsLogger("test").getOpStatsLogger("testLogger"); - logger.registerSuccessfulValue(1); - // the following should not throw any exception - OpStatsData statsData = logger.toOpStatsData(); - assertEquals(1, statsData.getNumSuccessfulEvents()); - } - - @Test - public void testToFastOpStatsData() { - OpStatsLogger logger = new FastCodahaleMetricsProvider().getStatsLogger("test").getOpStatsLogger("testLogger"); - logger.registerSuccessfulValue(1); - // the following should not throw any exception - OpStatsData statsData = logger.toOpStatsData(); - assertEquals(1, statsData.getNumSuccessfulEvents()); - } - -} diff --git a/stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/FastTimerTest.java b/stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/FastTimerTest.java deleted file mode 100644 index 0e900652cd9..00000000000 --- a/stats/bookkeeper-stats-providers/codahale-metrics-provider/src/test/java/org/apache/bookkeeper/stats/codahale/FastTimerTest.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * 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. - */ -package org.apache.bookkeeper.stats.codahale; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.codahale.metrics.Snapshot; -import java.util.ArrayList; -import java.util.Random; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Test; - -/** - * Unit tests for FastTimer. - * - */ -public class FastTimerTest { - - /* - * To simplify testing, we're over-riding the time source used by FastTimer with some - * fake time we're incrementing manually. This speeds-up testing (we don't have to wait - * for real seconds to elapse) and also guarantees deterministic behavior for the unit - * test. - */ - private static AtomicInteger mockedTime = new AtomicInteger(0); - - private int incSec() { - return mockedTime.incrementAndGet(); - } - - private FastTimer getMockedFastTimer(int timeWindowSeconds, FastTimer.Buckets buckets) { - return new FastTimer(timeWindowSeconds, buckets) { - @Override - protected int getTime() { - return mockedTime.get(); - } - }; - } - - @Test - public void testMeanRate() { - FastTimer t = getMockedFastTimer(1, FastTimer.Buckets.fine); - - t.update(10, TimeUnit.NANOSECONDS); - assertTrue("should calculate mean before advancing time", t.getMeanRate() > 0); - - incSec(); - assertTrue("should calculate mean after advancing time", t.getMeanRate() > 0); - } - - @Test - public void testBuckets() { - FastTimer t = new FastTimer(1, FastTimer.Buckets.fine); - for (int b = 0; b < t.getNumberOfBuckets(); b++) { - long lowerBound = b > 0 ? t.getBucketBound(b - 1) + 1 : 0; - long bucketMean = t.getBucketValue(b); - long upperBound = t.getBucketBound(b); - System.out.println(String.format("Bucket %3d [%12d - %12d], avg=%12d", - b, lowerBound, upperBound, bucketMean)); - assertEquals(String.format("bucket for lowerBound value %d", lowerBound), - b, t.getBucket(lowerBound)); - assertEquals(String.format("bucket for bucketMean value %d", bucketMean), - b, t.getBucket(bucketMean)); - assertEquals(String.format("bucket for upperBound value %d", upperBound), - b, t.getBucket(upperBound)); - if (b > 0) { - assertEquals(String.format("bucket before bucket %d", b), b - 1, t.getBucket(lowerBound - 1)); - } - if (b + 1 < t.getNumberOfBuckets()) { - assertEquals(String.format("bucket after bucket %d", b), b + 1, t.getBucket(upperBound + 1)); - } - } - } - - @Test - public void testFunctional() { - FastTimer t = getMockedFastTimer(1, FastTimer.Buckets.fine); - for (int i = 0; i <= 10000; i++) { - t.update(i, TimeUnit.MICROSECONDS); - } - incSec(); // advance mocked time to next second - Snapshot s = t.getSnapshot(); - assertEquals("FastTimer.getCount()", 10001, t.getCount()); - assertEquals("FastSnapshot.getMin()", 1, s.getMin()); - assertEquals("FastSnapshot.getMax()", TimeUnit.MICROSECONDS.toNanos(10000), s.getMax()); - assertEquals("FastSnapshot.getMean()", TimeUnit.MICROSECONDS.toNanos(5000), (long) s.getMean()); - assertEquals("FastSnapshot.getMedian()", TimeUnit.MICROSECONDS.toNanos(5000), (long) s.getMedian()); - assertEquals("FastSnapshot.getValue(0.1)", TimeUnit.MICROSECONDS.toNanos(1000), (long) s.getValue(0.1)); - assertEquals("FastSnapshot.getValue(0.9)", TimeUnit.MICROSECONDS.toNanos(9000), (long) s.getValue(0.9)); - assertEquals("FastSnapshot.getValue(0.99)", TimeUnit.MICROSECONDS.toNanos(9900), (long) s.getValue(0.99)); - } - - @Test - public void testTimer() { - // load definitions for testing the timer - // following 3 array lengths must match: each element defines values for one phase - final int[] timeRange = new int[] { 90, 190, 50, 90, 100, 100 }; - final int[] timeBase = new int[] { 10, 10, 50, 10, 0, 0 }; - final int[] rate = new int[] { 1000, 1000, 1000, 1000, 0, 1 }; - - final int window = 5; // use a 5 second window for testing - FastTimer t = getMockedFastTimer(window, FastTimer.Buckets.fine); - Random r = new Random(12345); // fixed random seed for deterministic value distribution - int phase = 0; - int sec = 0; - - long count = 0; - // start generating test load for each of the configured phases - while (phase < timeRange.length) { - for (int i = 0; i < rate[phase]; i++) { - t.update(r.nextInt(timeRange[phase]) + timeBase[phase], TimeUnit.MILLISECONDS); - count++; - } - incSec(); // advance mocked time to next second - if (++sec % window == 0) { - // every WINDOW seconds, check the timer values - Snapshot s = t.getSnapshot(); - System.out.println(String.format( - "phase %3d: count=%10d, rate=%6.0f, min=%6.1f, avg=%6.1f, q99=%6.1f, max=%6.1f", - phase, t.getCount(), t.getMeanRate(), ((double) s.getMin()) / 1000000.0, - s.getMean() / 1000000.0, s.getValue(0.99) / 1000000.0, ((double) s.getMax()) / 1000000.0)); - - // check count (events the timer has ever seen) - assertEquals("FastTimer.getCount()", count, t.getCount()); - // check rate (should be precisely the configured rate) - assertEquals("FastTimer.getMeanRate()", rate[phase], - (int) Math.round(t.getMeanRate())); - assertEquals("FastTimer.getOneMinuteRate()", rate[phase], - (int) Math.round(t.getOneMinuteRate())); - assertEquals("FastTimer.getFiveMinuteRate()", rate[phase], - (int) Math.round(t.getFiveMinuteRate())); - assertEquals("FastTimer.getFifteenMinuteRate()", rate[phase], - (int) Math.round(t.getFifteenMinuteRate())); - // at rates > 1000 (with fixed seed), we know that the following checks will be successful - if (t.getMeanRate() >= 1000) { - // check minimum value == lower bound - assertEquals("FastSnapshot.getMin()", timeBase[phase], s.getMin() / 1000000); - // check maximum value == upper bound - assertEquals("FastSnapshot.getMax()", timeBase[phase] + timeRange[phase] - 1, - (s.getMax() / 1000000)); - // check 99th percentile == upper bound - assertEquals("FastSnapshot.getValue(0.99)", - t.getBucketBound(t.getBucket( - TimeUnit.MILLISECONDS.toNanos(timeBase[phase] + timeRange[phase] - 1))), - (long) s.getValue(0.99)); - // check mean is within 10% of configured mean - assertEquals("FastSnapshot.getMean()", (timeBase[phase] + (timeRange[phase] / 2)) / 10, - (int) (Math.round(s.getMean() / 1000000) / 10)); - } - - // start next phase - phase++; - } - } - } - - @Test - public void testTimerMultiThreaded() { - final int window = 5; // use a 5 second window for testing - FastTimer t = getMockedFastTimer(window, FastTimer.Buckets.fine); - - // start 10 threads, which each update the timer 1000 times - ArrayList threads = new ArrayList(); - for (int i = 0; i < 10; i++) { - Thread thread = new Thread(() -> { - for (int j = 0; j < 1000; j++) { - t.update(10, TimeUnit.MILLISECONDS); - } - }); - threads.add(thread); - thread.start(); - } - // wait for 10 threads to finish - for (Thread thread : threads) { - try { - thread.join(); - } catch (InterruptedException e) { - // ignore - } - } - incSec(); // advance mocked time to next second - - assertEquals("FastTimer.getCount()", 10000, t.getCount()); - assertEquals("FastTimer.getMeanRate()", 2000, (int) Math.round(t.getMeanRate())); - - Snapshot s = t.getSnapshot(); - assertEquals("FastSnapshot.getMin()", 10, s.getMin() / 1000000); - assertEquals("FastSnapshot.getMax()", 10, (s.getMax() / 1000000)); - assertEquals("FastSnapshot.getValue(0.99)", 10, Math.round(s.getValue(0.99) / 1000000)); - assertEquals("FastSnapshot.getMean()", 10, (int) Math.round(s.getMean() / 1000000)); - } - - @Test - public void testTimerNoBuckets() { - final int window = 5; // use a 5 second window for testing - FastTimer t = getMockedFastTimer(window, FastTimer.Buckets.none); - - for (int i = 0; i < 1000; i++) { - t.update(10, TimeUnit.MILLISECONDS); - } - incSec(); // advance mocked time to next second - - assertEquals("FastTimer.getCount()", 1000, t.getCount()); - assertEquals("FastTimer.getMeanRate()", 200, (int) Math.round(t.getMeanRate())); - - Snapshot s = t.getSnapshot(); - assertEquals("FastSnapshot.getMin()", 10, s.getMin() / 1000000); - assertEquals("FastSnapshot.getMax()", 10, (s.getMax() / 1000000)); - assertEquals("FastSnapshot.getValue(0.99)", 0, Math.round(s.getValue(0.99) / 1000000)); - assertEquals("FastSnapshot.getMean()", 10, (int) Math.round(s.getMean() / 1000000)); - } - - @Test - public void testSnapshotOutOfSync() { - FastTimer t = getMockedFastTimer(1, FastTimer.Buckets.fine); - t.update(t.getBucketBound(0) - 1, TimeUnit.NANOSECONDS); // add value to 1st bucket - t.update(t.getBucketBound(1) - 1, TimeUnit.NANOSECONDS); // add value to 2nd bucket - t.update(t.getBucketBound(2) - 1, TimeUnit.NANOSECONDS); // add value to 3rd bucket - incSec(); // advance mocked time to next second - Snapshot s1 = t.getSnapshot(); - long[] buckets = new long[t.getNumberOfBuckets()]; - buckets[0] = 1; - buckets[1] = 1; - buckets[2] = 1; - Snapshot s2 = new FastSnapshot(t, - t.getBucketBound(0) - 1, - t.getBucketBound(2) - 1, - t.getBucketBound(0) + t.getBucketBound(1) + t.getBucketBound(2) + 3, - 4, // count (4) is out of sync with number of recorded events in buckets (3) - buckets); - assertEquals("FastSnapshot.getMin()", s1.getMin(), s2.getMin()); - assertEquals("FastSnapshot.getMax()", s1.getMax(), s2.getMax()); - assertEquals("FastSnapshot.getValue(0.95)", (long) s1.getValue(0.95), (long) s2.getValue(0.95)); - } - -} diff --git a/stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusFormatter.java b/stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusFormatter.java deleted file mode 100644 index 8855044f24a..00000000000 --- a/stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusFormatter.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * 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. - */ -package org.apache.bookkeeper.stats.prometheus; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.base.MoreObjects; -import com.google.common.base.Splitter; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; -import io.prometheus.client.CollectorRegistry; -import io.prometheus.client.Gauge; -import io.prometheus.client.hotspot.GarbageCollectorExports; -import io.prometheus.client.hotspot.MemoryPoolsExports; -import io.prometheus.client.hotspot.StandardExports; -import io.prometheus.client.hotspot.ThreadExports; -import java.io.IOException; -import java.io.StringWriter; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.junit.Test; - -/** - * Test for {@link PrometheusMetricsProvider}. - */ -public class TestPrometheusFormatter { - - @Test(timeout = 30000) - public void testStatsOutput() throws Exception { - PrometheusMetricsProvider provider = new PrometheusMetricsProvider(); - StatsLogger statsLogger = provider.getStatsLogger("test"); - Counter counter = statsLogger.getCounter("my_counter"); - - counter.inc(); - counter.inc(); - - OpStatsLogger opStats = statsLogger.getOpStatsLogger("op"); - opStats.registerSuccessfulEvent(10, TimeUnit.MILLISECONDS); - opStats.registerSuccessfulEvent(5, TimeUnit.MILLISECONDS); - - OpStatsLogger opStats1 = statsLogger.scopeLabel("test_label", "test_value") - .getOpStatsLogger("op_label"); - opStats1.registerSuccessfulEvent(10, TimeUnit.MILLISECONDS); - opStats1.registerSuccessfulEvent(5, TimeUnit.MILLISECONDS); - opStats1.registerFailedEvent(1, TimeUnit.MILLISECONDS); - - provider.rotateLatencyCollection(); - - StringWriter writer = new StringWriter(); - provider.writeAllMetrics(writer); - - writer.write("jvm_memory_direct_bytes_max{} 4.77626368E8\n"); - writer.write("jvm_memory_pool_bytes_used{pool=\"Code Cache\"} 3347712.0\n"); - writer.write("jvm_memory_pool_bytes_used{pool=\"CodeHeap 'non-nmethods'\"} 1207168.0\n"); - System.out.println(writer); - Multimap metrics = parseMetrics(writer.toString()); - System.out.println(metrics); - - List cm = (List) metrics.get("test_my_counter"); - assertEquals(1, cm.size()); - assertEquals(0, cm.get(0).tags.size()); - assertEquals(2.0, cm.get(0).value, 0.0); - - // test_op_sum - cm = (List) metrics.get("test_op_sum"); - assertEquals(2, cm.size()); - Metric m = cm.get(0); - assertEquals(1, cm.get(0).tags.size()); - assertEquals(0.0, m.value, 0.0); - assertEquals(1, m.tags.size()); - assertEquals("false", m.tags.get("success")); - - m = cm.get(1); - assertEquals(1, cm.get(0).tags.size()); - assertEquals(15.0, m.value, 0.0); - assertEquals(1, m.tags.size()); - assertEquals("true", m.tags.get("success")); - - // test_op_count - cm = (List) metrics.get("test_op_count"); - assertEquals(2, cm.size()); - m = cm.get(0); - assertEquals(1, cm.get(0).tags.size()); - assertEquals(0.0, m.value, 0.0); - assertEquals(1, m.tags.size()); - assertEquals("false", m.tags.get("success")); - - m = cm.get(1); - assertEquals(1, cm.get(0).tags.size()); - assertEquals(2.0, m.value, 0.0); - assertEquals(1, m.tags.size()); - assertEquals("true", m.tags.get("success")); - - // Latency - cm = (List) metrics.get("test_op"); - assertEquals(14, cm.size()); - - boolean found = false; - for (Metric mt : cm) { - if ("true".equals(mt.tags.get("success")) && "1.0".equals(mt.tags.get("quantile"))) { - assertEquals(10.0, mt.value, 0.0); - found = true; - } - } - - assertTrue(found); - - // test_op_label_sum - cm = (List) metrics.get("test_op_label_sum"); - assertEquals(2, cm.size()); - m = cm.get(0); - assertEquals(2, m.tags.size()); - assertEquals(1.0, m.value, 0.0); - assertEquals("false", m.tags.get("success")); - assertEquals("test_value", m.tags.get("test_label")); - - m = cm.get(1); - assertEquals(15.0, m.value, 0.0); - assertEquals(2, m.tags.size()); - assertEquals("true", m.tags.get("success")); - assertEquals("test_value", m.tags.get("test_label")); - - // test_op_label_count - cm = (List) metrics.get("test_op_label_count"); - assertEquals(2, cm.size()); - m = cm.get(0); - assertEquals(1, m.value, 0.0); - assertEquals(2, m.tags.size()); - assertEquals("false", m.tags.get("success")); - assertEquals("test_value", m.tags.get("test_label")); - - m = cm.get(1); - assertEquals(2.0, m.value, 0.0); - assertEquals(2, m.tags.size()); - assertEquals("true", m.tags.get("success")); - assertEquals("test_value", m.tags.get("test_label")); - - // Latency - cm = (List) metrics.get("test_op_label"); - assertEquals(14, cm.size()); - - found = false; - for (Metric mt : cm) { - if ("true".equals(mt.tags.get("success")) - && "test_value".equals(mt.tags.get("test_label")) - && "1.0".equals(mt.tags.get("quantile"))) { - assertEquals(10.0, mt.value, 0.0); - found = true; - } - } - - assertTrue(found); - } - - @Test - public void testWriteMetricsCollectedByPrometheusClient() { - CollectorRegistry registry = CollectorRegistry.defaultRegistry; - registry.register(new StandardExports()); - registry.register(new MemoryPoolsExports()); - registry.register(new GarbageCollectorExports()); - registry.register(new ThreadExports()); - registry.register(Gauge.build("jvm_memory_direct_bytes_used", "-").create().setChild(new Gauge.Child() { - @Override - public double get() { - return 1.0; - } - })); - registry.register(Gauge.build("jvm_memory_direct_bytes_max", "-").create().setChild(new Gauge.Child() { - @Override - public double get() { - return 100.0; - } - })); - PrometheusMetricsProvider provider = new PrometheusMetricsProvider(registry); - StringWriter writer = new StringWriter(); - try { - provider.rotateLatencyCollection(); - provider.writeAllMetrics(writer); - String output = writer.toString(); - parseMetrics(output); - assertTrue(output.contains("# TYPE jvm_memory_direct_bytes_max gauge")); - assertTrue(output.contains("# TYPE jvm_memory_direct_bytes_used gauge")); - assertTrue(output.contains("# TYPE jvm_gc_collection_seconds summary")); - assertTrue(output.contains("# TYPE jvm_memory_pool_bytes_committed gauge")); - assertTrue(output.contains("# TYPE process_cpu_seconds counter")); - } catch (Exception e) { - fail(); - } - - } - - @Test - public void testPrometheusTypeDuplicate() throws IOException { - PrometheusTextFormat prometheusTextFormat = new PrometheusTextFormat(); - StringWriter writer = new StringWriter(); - prometheusTextFormat.writeType(writer, "counter", "gauge"); - prometheusTextFormat.writeType(writer, "counter", "gauge"); - String string = writer.toString(); - assertEquals("# TYPE counter gauge\n", string); - } - - - /** - * Hacky parsing of Prometheus text format. Sould be good enough for unit tests - */ - private static Multimap parseMetrics(String metrics) { - Multimap parsed = ArrayListMultimap.create(); - - // Example of lines are - // jvm_threads_current{cluster="standalone",} 203.0 - // or - // pulsar_subscriptions_count{cluster="standalone", namespace="sample/standalone/ns1", - // topic="persistent://sample/standalone/ns1/test-2"} 0.0 1517945780897 - Pattern pattern = Pattern.compile("^(\\w+)(\\{([^\\}]*)\\})?\\s(-?[\\d\\w\\.]+)(\\s(\\d+))?$"); - Pattern formatPattern = - Pattern.compile("^(\\w+)(\\{((\\w+=[-\\s\\\'\\\"\\.\\w]+(,\\s?\\w+=[\\\"\\.\\w]+)*))?\\})?" - + "\\s(-?[\\d\\w\\.]+)(\\s(\\d+))?$"); - Pattern tagsPattern = Pattern.compile("(\\w+)=\"([^\"]+)\"(,\\s?)?"); - - Splitter.on("\n").split(metrics).forEach(line -> { - if (line.isEmpty() || line.startsWith("#")) { - return; - } - - System.err.println("LINE: '" + line + "'"); - Matcher matcher = pattern.matcher(line); - Matcher formatMatcher = formatPattern.matcher(line); - System.err.println("Matches: " + matcher.matches()); - System.err.println(matcher); - assertTrue(matcher.matches()); - assertTrue("failed to validate line: " + line, formatMatcher.matches()); - - assertEquals(6, matcher.groupCount()); - System.err.println("groups: " + matcher.groupCount()); - for (int i = 0; i < matcher.groupCount(); i++) { - System.err.println(" GROUP " + i + " -- " + matcher.group(i)); - } - - checkArgument(matcher.matches()); - checkArgument(formatMatcher.matches()); - String name = matcher.group(1); - - Metric m = new Metric(); - m.value = Double.parseDouble(matcher.group(4)); - - String tags = matcher.group(3); - if (tags != null) { - Matcher tagsMatcher = tagsPattern.matcher(tags); - while (tagsMatcher.find()) { - String tag = tagsMatcher.group(1); - String value = tagsMatcher.group(2); - m.tags.put(tag, value); - } - } - - parsed.put(name, m); - }); - - return parsed; - } - - static class Metric { - Map tags = new TreeMap<>(); - double value; - - @Override - public String toString() { - return MoreObjects.toStringHelper(this).add("tags", tags).add("value", value).toString(); - } - } -} diff --git a/stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java b/stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java deleted file mode 100644 index 6f1b1962832..00000000000 --- a/stats/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * 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. - */ -package org.apache.bookkeeper.stats.prometheus; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.io.StringWriter; -import java.util.Collections; -import java.util.HashMap; -import java.util.concurrent.TimeUnit; -import lombok.Cleanup; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test of {@link PrometheusMetricsProvider}. - */ -public class TestPrometheusMetricsProvider { - - @Test - public void testStartNoHttp() { - PropertiesConfiguration config = new PropertiesConfiguration(); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ENABLE, false); - PrometheusMetricsProvider provider = new PrometheusMetricsProvider(); - try { - provider.start(config); - assertNull(provider.server); - } finally { - provider.stop(); - } - } - - @Test - public void testStartNoHttpWhenBkHttpEnabled() { - PropertiesConfiguration config = new PropertiesConfiguration(); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ENABLE, true); - config.setProperty("httpServerEnabled", true); - @Cleanup("stop") PrometheusMetricsProvider provider = new PrometheusMetricsProvider(); - provider.start(config); - assertNull(provider.server); - } - - @Test - public void testStartWithHttp() { - PropertiesConfiguration config = new PropertiesConfiguration(); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ENABLE, true); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_PORT, 0); // ephemeral - PrometheusMetricsProvider provider = new PrometheusMetricsProvider(); - try { - provider.start(config); - assertNotNull(provider.server); - } finally { - provider.stop(); - } - } - - @Test - public void testStartWithHttpSpecifyAddr() { - PropertiesConfiguration config = new PropertiesConfiguration(); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ENABLE, true); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_PORT, 0); // ephemeral - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ADDRESS, "127.0.0.1"); - PrometheusMetricsProvider provider = new PrometheusMetricsProvider(); - try { - provider.start(config); - assertNotNull(provider.server); - } finally { - provider.stop(); - } - } - - @Test - public void testCounter() { - LongAdderCounter counter = new LongAdderCounter(Collections.emptyMap()); - long value = counter.get(); - assertEquals(0L, value); - counter.inc(); - assertEquals(1L, counter.get().longValue()); - counter.dec(); - assertEquals(0L, counter.get().longValue()); - counter.addCount(3); - assertEquals(3L, counter.get().longValue()); - } - - @Test - public void testCounter2() { - LongAdderCounter counter = new LongAdderCounter(Collections.emptyMap()); - long value = counter.get(); - assertEquals(0L, value); - counter.addLatency(3 * 1000 * 1000L, TimeUnit.NANOSECONDS); - assertEquals(3L, counter.get().longValue()); - } - - @Test - public void testTwoCounters() throws Exception { - PrometheusMetricsProvider provider = new PrometheusMetricsProvider(); - StatsLogger statsLogger = provider.getStatsLogger("test"); - - Counter counter1 = statsLogger.getCounter("counter"); - Counter counter2 = statsLogger.getCounter("counter"); - assertEquals(counter1, counter2); - assertSame(counter1, counter2); - - assertEquals(1, provider.counters.size()); - } - - @Test - public void testJvmDirectMemoryMetrics() throws Exception { - PropertiesConfiguration config = new PropertiesConfiguration(); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ENABLE, true); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_PORT, 0); - config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ADDRESS, "127.0.0.1"); - ByteBuf byteBuf = ByteBufAllocator.DEFAULT.directBuffer(25); - PrometheusMetricsProvider provider = new PrometheusMetricsProvider(); - try { - provider.start(config); - assertNotNull(provider.server); - StringWriter writer = new StringWriter(); - provider.writeAllMetrics(writer); - String s = writer.toString(); - String[] split = s.split(System.lineSeparator()); - HashMap map = new HashMap<>(); - for (String str : split) { - String[] aux = str.split(" "); - map.put(aux[0], aux[1]); - } - String directBytesMax = map.get("jvm_memory_direct_bytes_max{}"); - Assert.assertNotNull(directBytesMax); - Assert.assertNotEquals("Nan", directBytesMax); - Assert.assertNotEquals("-1", directBytesMax); - String directBytesUsed = map.get("jvm_memory_direct_bytes_used{}"); - Assert.assertNotNull(directBytesUsed); - Assert.assertNotEquals("Nan", directBytesUsed); - Assert.assertTrue(Double.parseDouble(directBytesUsed) > 25); - // ensure byteBuffer doesn't gc - byteBuf.release(); - } finally { - provider.stop(); - } - } - -} diff --git a/stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/BKRegistrationNameResolverTest.java b/stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/BKRegistrationNameResolverTest.java deleted file mode 100644 index dfad2230526..00000000000 --- a/stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/BKRegistrationNameResolverTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.grpc.resolver; - -import static org.apache.bookkeeper.util.BookKeeperConstants.AVAILABLE_NODE; -import static org.junit.Assert.assertEquals; - -import io.grpc.Attributes; -import io.grpc.EquivalentAddressGroup; -import io.grpc.NameResolver; -import io.grpc.NameResolver.Listener; -import io.grpc.Status; -import io.grpc.SynchronizationContext; -import io.grpc.internal.GrpcUtil; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.net.URI; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.stream.Collectors; -import lombok.Cleanup; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.BookieServiceInfo; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.test.BookKeeperClusterTestCase; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs.Ids; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link BKRegistrationNameResolver}. - */ -public class BKRegistrationNameResolverTest extends BookKeeperClusterTestCase { - - private static final String ROOT_PATH = "/resolver-test"; - private static final String SERVERS_PATH = ROOT_PATH + "/servers"; - - private final BKRegistrationNameResolverProvider resolverProvider; - - private MetadataBookieDriver bookieDriver; - private RegistrationManager regManager; - private URI serviceUri; - - public BKRegistrationNameResolverTest() { - super(0); - this.resolverProvider = new BKRegistrationNameResolverProvider(); - } - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - - zkc.transaction() - .create(ROOT_PATH, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT) - .create(SERVERS_PATH, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT) - .create(SERVERS_PATH + "/" + AVAILABLE_NODE, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT) - .commit(); - - serviceUri = URI.create("zk://" + zkUtil.getZooKeeperConnectString() + SERVERS_PATH); - - - ServerConfiguration serverConf = new ServerConfiguration(); - serverConf.setMetadataServiceUri(serviceUri.toString()); - bookieDriver = MetadataDrivers.getBookieDriver(serviceUri); - bookieDriver.initialize(serverConf, NullStatsLogger.INSTANCE); - regManager = bookieDriver.createRegistrationManager(); - } - - @After - @Override - public void tearDown() throws Exception { - regManager.close(); - bookieDriver.close(); - - super.tearDown(); - } - - @Test - public void testNameResolver() throws Exception { - int numServers = 3; - - Set addressSet = new HashSet<>(); - for (int i = 0; i < numServers; i++) { - InetSocketAddress address = new InetSocketAddress("127.0.0.1", 3181 + i); - addressSet.add(address); - bookieDriver.createRegistrationManager().registerBookie( - BookieId.parse("127.0.0.1:" + (3181 + i)), false, BookieServiceInfo.EMPTY - ); - } - - LinkedBlockingQueue> notifications = new LinkedBlockingQueue<>(); - - - @Cleanup("shutdown") - NameResolver resolver = resolverProvider.newNameResolver(serviceUri, - NameResolver.Args.newBuilder() - .setDefaultPort(0) - .setProxyDetector(GrpcUtil.DEFAULT_PROXY_DETECTOR) - .setSynchronizationContext(new SynchronizationContext((t, ex) -> {})) - .setServiceConfigParser(new NameResolver.ServiceConfigParser() { - @Override - public NameResolver.ConfigOrError parseServiceConfig(Map rawServiceConfig) { - return null; - } - }) - .build()); - resolver.start(new Listener() { - @Override - public void onAddresses(List servers, Attributes attributes) { - notifications.add(servers); - } - - @Override - public void onError(Status error) { - - } - }); - - List groups = notifications.take(); - assertEquals(numServers, groups.size()); - - Set receivedSet = groups.stream() - .map(group -> group.getAddresses().get(0)) - .collect(Collectors.toSet()); - assertEquals(addressSet, receivedSet); - - // add 3 more servers - - for (int i = numServers; i < 2 * numServers; i++) { - InetSocketAddress address = new InetSocketAddress("127.0.0.1", 3181 + i); - addressSet.add(address); - regManager.registerBookie( - BookieId.parse("127.0.0.1:" + (3181 + i)), false, BookieServiceInfo.EMPTY - ); - } - - List notification = notifications.take(); - while (notification.size() < 2 * numServers) { - notification = notifications.take(); - } - assertEquals(2 * numServers, notification.size()); - receivedSet = notification.stream() - .map(group -> group.getAddresses().get(0)) - .collect(Collectors.toSet()); - assertEquals(addressSet, receivedSet); - } - -} diff --git a/stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/GrpcChannelsTest.java b/stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/GrpcChannelsTest.java deleted file mode 100644 index 9df1bf1deb8..00000000000 --- a/stream/bk-grpc-name-resolver/src/test/java/org/apache/bookkeeper/grpc/resolver/GrpcChannelsTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.grpc.resolver; - -import static org.junit.Assert.assertTrue; - -import io.grpc.ManagedChannelBuilder; -import io.grpc.netty.NettyChannelBuilder; -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.apache.bookkeeper.clients.utils.GrpcChannels; -import org.junit.Test; - -/** - * Unit test {@link org.apache.bookkeeper.clients.utils.GrpcChannels} with registration based name resolver. - */ -public class GrpcChannelsTest { - - @Test - public void testZKServiceUri() { - String serviceUri = "zk://127.0.0.1/stream/servers"; - ManagedChannelBuilder builder = GrpcChannels.createChannelBuilder( - serviceUri, - StorageClientSettings.newBuilder().serviceUri(serviceUri).build()); - assertTrue(builder instanceof NettyChannelBuilder); - } - -} diff --git a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/StorageClientImplTest.java b/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/StorageClientImplTest.java deleted file mode 100644 index 56f99d424ee..00000000000 --- a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/StorageClientImplTest.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.api.exceptions.ApiException; -import org.apache.bookkeeper.api.kv.PTable; -import org.apache.bookkeeper.api.kv.Table; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.kv.ByteBufTableImpl; -import org.apache.bookkeeper.clients.impl.kv.PByteBufTableImpl; -import org.apache.bookkeeper.clients.utils.ClientResources; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.StorageType; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Unit test {@link StorageClientImpl}. - */ -@RunWith(MockitoJUnitRunner.class) -@Slf4j -public class StorageClientImplTest extends GrpcClientTestBase { - - private static final String NAMESPACE = "test-namespace"; - private static final String STREAM_NAME = "test-stream-name"; - private static final StreamProperties STREAM_PROPERTIES = StreamProperties.newBuilder() - .setStreamId(1234L) - .setStreamConf(DEFAULT_STREAM_CONF) - .setStreamName(STREAM_NAME) - .setStorageContainerId(16) - .build(); - - private StorageClientImpl client; - - @Override - protected void doSetup() { - this.client = spy(new StorageClientImpl( - NAMESPACE, - settings, - ClientResources.create() - )); - } - - @Override - protected void doTeardown() { - this.client.close(); - } - - @SuppressWarnings("unchecked") - @Test - public void testOpenPTable() throws Exception { - StreamProperties streamProps = StreamProperties.newBuilder(STREAM_PROPERTIES) - .setStreamConf(StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build()) - .build(); - when(client.getStreamProperties(anyString(), anyString())) - .thenReturn(FutureUtils.value(streamProps)); - - PByteBufTableImpl tableImpl = mock(PByteBufTableImpl.class); - when(tableImpl.initialize()).thenReturn(FutureUtils.value(tableImpl)); - - doReturn(tableImpl).when(client).newPByteBufTableImpl(anyString(), any(StreamProperties.class)); - - PTable returnedTableImpl = FutureUtils.result( - client.openPTable(STREAM_NAME) - ); - - assertSame(tableImpl, returnedTableImpl); - } - - @SuppressWarnings("unchecked") - @Test - public void testOpenPTableDiffernetNamespace() throws Exception { - StreamProperties tableProps1 = StreamProperties.newBuilder(STREAM_PROPERTIES) - .setStreamName("table1") - .setStreamConf(StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build()) - .build(); - when(client.getStreamProperties(eq(NAMESPACE), eq("table1"))) - .thenReturn(FutureUtils.value(tableProps1)); - - StreamProperties tableProps2 = StreamProperties.newBuilder(STREAM_PROPERTIES) - .setStreamName("table2") - .setStreamConf(StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build()) - .build(); - when(client.getStreamProperties(eq(NAMESPACE), eq("table2"))) - .thenReturn(FutureUtils.value(tableProps2)); - - PByteBufTableImpl tableImpl1 = mock(PByteBufTableImpl.class); - when(tableImpl1.initialize()).thenReturn(FutureUtils.value(tableImpl1)); - PByteBufTableImpl tableImpl2 = mock(PByteBufTableImpl.class); - when(tableImpl2.initialize()).thenReturn(FutureUtils.value(tableImpl2)); - - doReturn(tableImpl1).when(client).newPByteBufTableImpl(anyString(), any(StreamProperties.class)); - - PTable returnedTableImpl1 = FutureUtils.result( - client.openPTable("table1") - ); - assertSame(tableImpl1, returnedTableImpl1); - - doReturn(tableImpl2).when(client).newPByteBufTableImpl(anyString(), any(StreamProperties.class)); - - PTable returnedTableImpl2 = FutureUtils.result( - client.openPTable("table2") - ); - assertSame(tableImpl2, returnedTableImpl2); - } - - @SuppressWarnings("unchecked") - @Test - public void testOpenTable() throws Exception { - StreamProperties streamProps = StreamProperties.newBuilder(STREAM_PROPERTIES) - .setStreamConf(StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build()) - .build(); - when(client.getStreamProperties(anyString(), anyString())) - .thenReturn(FutureUtils.value(streamProps)); - - PByteBufTableImpl tableImpl = mock(PByteBufTableImpl.class); - when(tableImpl.initialize()).thenReturn(FutureUtils.value(tableImpl)); - - doReturn(tableImpl).when(client).newPByteBufTableImpl(anyString(), any(StreamProperties.class)); - - Table returnedTableImpl = FutureUtils.result( - client.openTable(STREAM_NAME) - ); - assertTrue(returnedTableImpl instanceof ByteBufTableImpl); - ByteBufTableImpl bytesTableImpl = (ByteBufTableImpl) returnedTableImpl; - - assertSame(tableImpl, bytesTableImpl.getUnderlying()); - } - - @SuppressWarnings("unchecked") - @Test - public void testOpenTableWithDifferentNamespace() throws Exception { - StreamProperties tableProps1 = StreamProperties.newBuilder(STREAM_PROPERTIES) - .setStreamName("table1") - .setStreamConf(StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build()) - .build(); - when(client.getStreamProperties(eq(NAMESPACE), eq("table1"))) - .thenReturn(FutureUtils.value(tableProps1)); - - StreamProperties tableProps2 = StreamProperties.newBuilder(STREAM_PROPERTIES) - .setStreamName("table2") - .setStreamConf(StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build()) - .build(); - when(client.getStreamProperties(eq(NAMESPACE), eq("table2"))) - .thenReturn(FutureUtils.value(tableProps2)); - - PByteBufTableImpl tableImpl1 = mock(PByteBufTableImpl.class); - when(tableImpl1.initialize()).thenReturn(FutureUtils.value(tableImpl1)); - PByteBufTableImpl tableImpl2 = mock(PByteBufTableImpl.class); - when(tableImpl2.initialize()).thenReturn(FutureUtils.value(tableImpl2)); - - doReturn(tableImpl1).when(client).newPByteBufTableImpl(anyString(), any(StreamProperties.class)); - - Table returnedTableImpl1 = FutureUtils.result( - client.openTable("table1") - ); - assertTrue(returnedTableImpl1 instanceof ByteBufTableImpl); - ByteBufTableImpl bytesTableImpl1 = (ByteBufTableImpl) returnedTableImpl1; - assertSame(tableImpl1, bytesTableImpl1.getUnderlying()); - - doReturn(tableImpl2).when(client).newPByteBufTableImpl(anyString(), any(StreamProperties.class)); - - Table returnedTableImpl2 = FutureUtils.result( - client.openTable("table2") - ); - assertTrue(returnedTableImpl2 instanceof ByteBufTableImpl); - ByteBufTableImpl bytesTableImpl2 = (ByteBufTableImpl) returnedTableImpl2; - assertSame(tableImpl2, bytesTableImpl2.getUnderlying()); - } - - @SuppressWarnings("unchecked") - @Test - public void testOpenPTableIllegalOp() throws Exception { - StreamProperties streamProps = StreamProperties.newBuilder(STREAM_PROPERTIES) - .setStreamConf(StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.STREAM) - .build()) - .build(); - when(client.getStreamProperties(anyString(), anyString())) - .thenReturn(FutureUtils.value(streamProps)); - - try { - FutureUtils.result(client.openPTable(STREAM_NAME)); - fail("Should fail #openTable on opening a non-table storage entity"); - } catch (ApiException sae) { - // expected exception - } - } -} diff --git a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java b/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java deleted file mode 100644 index daef4ed332e..00000000000 --- a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients; - -import static org.mockito.Mockito.mock; - -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.junit.Test; - -/** - * Unit test of {@link StorageClientBuilder}. - */ -public class TestStorageClientBuilder { - - @Test(expected = NullPointerException.class) - public void testBuildClientNullSettings() { - StorageClientBuilder.newBuilder() - .withSettings(null) - .withNamespace("namespace") - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void testBuildClientNullNamespaceName() { - StorageClientBuilder.newBuilder() - .withSettings(mock(StorageClientSettings.class)) - .withNamespace(null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void testBuildClientInvalidNamespaceName() { - StorageClientBuilder.newBuilder() - .withSettings(StorageClientSettings.newBuilder() - .serviceUri("bk://localhost:4181") - .build()) - .withNamespace("invalid namespace") - .build(); - } - -} diff --git a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/admin/TestStorageAdminClientImpl.java b/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/admin/TestStorageAdminClientImpl.java deleted file mode 100644 index d9a791a5efb..00000000000 --- a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/admin/TestStorageAdminClientImpl.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.admin; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.clients.impl.internal.api.StorageServerClientManager; -import org.apache.bookkeeper.clients.utils.ClientResources; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test for {@link StorageAdminClientImpl}. - */ -public class TestStorageAdminClientImpl { - - private static final NamespaceConfiguration colConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - private static final NamespaceProperties colProps = NamespaceProperties.newBuilder() - .setNamespaceId(System.currentTimeMillis()) - .setNamespaceName("namespace") - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - private static final StreamProperties streamProps = StreamProperties.newBuilder() - .setStreamId(System.currentTimeMillis()) - .setStorageContainerId(System.currentTimeMillis()) - .setStreamName("stream_" + System.currentTimeMillis()) - .setStreamConf(DEFAULT_STREAM_CONF) - .build(); - - @Rule - public TestName testName = new TestName(); - - private RootRangeClient mockRootRangeClient = mock(RootRangeClient.class); - private StorageServerClientManager mockManager = mock(StorageServerClientManager.class); - private StorageAdminClientImpl adminClient; - - @Before - public void setUp() { - when(mockManager.getRootRangeClient()).thenReturn(mockRootRangeClient); - this.adminClient = new StorageAdminClientImpl( - StorageClientSettings.newBuilder() - .serviceUri("bk://localhost:4181") - .build(), - ClientResources.create(), - () -> mockManager); - } - - @Test - public void testCreateNamespace() throws Exception { - String colName = testName.getMethodName(); - when(mockRootRangeClient.createNamespace(colName, colConf)) - .thenReturn(FutureUtils.value(colProps)); - assertEquals(colProps, FutureUtils.result(adminClient.createNamespace(colName, colConf))); - verify(mockRootRangeClient, times(1)).createNamespace(colName, colConf); - } - - @Test - public void testDeleteNamespace() throws Exception { - String colName = testName.getMethodName(); - when(mockRootRangeClient.deleteNamespace(colName)) - .thenReturn(FutureUtils.value(true)); - assertEquals(true, FutureUtils.result(adminClient.deleteNamespace(colName))); - verify(mockRootRangeClient, times(1)).deleteNamespace(colName); - } - - @Test - public void testGetNamespace() throws Exception { - String colName = testName.getMethodName(); - when(mockRootRangeClient.getNamespace(colName)) - .thenReturn(FutureUtils.value(colProps)); - assertEquals(colProps, FutureUtils.result(adminClient.getNamespace(colName))); - verify(mockRootRangeClient, times(1)).getNamespace(colName); - } - - @Test - public void testCreateStream() throws Exception { - String colName = testName.getMethodName(); - String streamName = colName + "_stream"; - when(mockRootRangeClient.createStream(colName, streamName, DEFAULT_STREAM_CONF)) - .thenReturn(FutureUtils.value(streamProps)); - assertEquals(streamProps, FutureUtils.result( - adminClient.createStream(colName, streamName, DEFAULT_STREAM_CONF))); - verify(mockRootRangeClient, times(1)).createStream(colName, streamName, DEFAULT_STREAM_CONF); - } - - @Test - public void testDeleteStream() throws Exception { - String colName = testName.getMethodName(); - String streamName = colName + "_stream"; - when(mockRootRangeClient.deleteStream(colName, streamName)) - .thenReturn(FutureUtils.value(true)); - assertEquals(true, FutureUtils.result(adminClient.deleteStream(colName, streamName))); - verify(mockRootRangeClient, times(1)).deleteStream(colName, streamName); - } - - @Test - public void testGetStream() throws Exception { - String colName = testName.getMethodName(); - String streamName = colName + "_stream"; - when(mockRootRangeClient.getStream(colName, streamName)) - .thenReturn(FutureUtils.value(streamProps)); - assertEquals(streamProps, FutureUtils.result(adminClient.getStream(colName, streamName))); - verify(mockRootRangeClient, times(1)).getStream(colName, streamName); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java deleted file mode 100644 index a4e4294fc00..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.junit.Test; - -/** - * Unit test for {@link StorageClientSettings}. - */ -public class TestStorageClientSettings { - - @Test - public void testDefault() { - StorageClientSettings settings = StorageClientSettings.newBuilder() - .serviceUri("bk://127.0.0.1:4181/") - .build(); - assertEquals("bk://127.0.0.1:4181/", settings.serviceUri()); - assertEquals(Runtime.getRuntime().availableProcessors(), settings.numWorkerThreads()); - assertTrue(settings.usePlaintext()); - assertFalse(settings.clientName().isPresent()); - } - - @Test - public void testEmptyBuilder() { - try { - StorageClientSettings.newBuilder().build(); - fail("Should fail with missing endpoints"); - } catch (IllegalStateException iae) { - assertEquals("Not set: [serviceUri]", iae.getMessage()); - } - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java deleted file mode 100644 index de5169444d9..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.grpc; - -import io.grpc.Server; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.stub.StreamObserver; -import io.grpc.util.MutableHandlerRegistry; -import java.util.Optional; -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.internal.StorageServerClientManagerImpl; -import org.apache.bookkeeper.clients.utils.ClientResources; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerServiceGrpc.StorageContainerServiceImplBase; -import org.junit.After; -import org.junit.Before; - -/** - * Test Base for Grpc related tests. - */ -public abstract class GrpcClientTestBase { - - protected static final Endpoint ENDPOINT = Endpoint.newBuilder() - .setHostname("127.0.0.1") - .setPort(4181) - .build(); - - protected String serverName; - protected final MutableHandlerRegistry serviceRegistry = new MutableHandlerRegistry(); - protected Server fakeServer; - protected OrderedScheduler scheduler; - - protected StorageClientSettings settings; - protected final ClientResources resources = ClientResources.create(); - protected StorageServerClientManagerImpl serverManager; - - @Before - public void setUp() throws Exception { - serverName = "fake-server:4181"; - fakeServer = InProcessServerBuilder - .forName(serverName) - .fallbackHandlerRegistry(serviceRegistry) - .directExecutor() - .build() - .start(); - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("scheduler-" + getClass()) - .numThreads(Runtime.getRuntime().availableProcessors()) - .build(); - settings = StorageClientSettings.newBuilder() - .serviceUri("bk+inprocess://" + serverName) - .build(); - serverManager = new StorageServerClientManagerImpl( - settings, - resources.scheduler(), - endpoint -> new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty())); - StorageContainerServiceImplBase scService = new StorageContainerServiceImplBase() { - @Override - public void getStorageContainerEndpoint( - GetStorageContainerEndpointRequest request, - StreamObserver responseObserver) { - GetStorageContainerEndpointResponse.Builder respBuilder = - GetStorageContainerEndpointResponse.newBuilder(); - respBuilder.setStatusCode(StatusCode.SUCCESS); - for (OneStorageContainerEndpointRequest oneReq : request.getRequestsList()) { - OneStorageContainerEndpointResponse oneResp = OneStorageContainerEndpointResponse.newBuilder() - .setEndpoint(StorageContainerEndpoint.newBuilder() - .setStorageContainerId(oneReq.getStorageContainer()) - .setRevision(oneReq.getRevision() + 1) - .setRwEndpoint(ENDPOINT)) - .build(); - respBuilder.addResponses(oneResp); - } - responseObserver.onNext(respBuilder.build()); - responseObserver.onCompleted(); - } - }; - serviceRegistry.addService(scService.bindService()); - - doSetup(); - } - - protected abstract void doSetup() throws Exception; - - @After - public void tearDown() throws Exception { - doTeardown(); - if (null != serverManager) { - serverManager.close(); - } - if (null != fakeServer) { - fakeServer.shutdown(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - } - - protected abstract void doTeardown() throws Exception; - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannel.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannel.java deleted file mode 100644 index e1260665ad0..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannel.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.channel; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import io.grpc.ManagedChannel; -import io.grpc.Server; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.util.MutableHandlerRegistry; -import java.util.Optional; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link StorageServerChannel}. - */ -public class TestStorageServerChannel { - - private final String serverName = "fake server for " + getClass(); - private final MutableHandlerRegistry serviceRegistry = new MutableHandlerRegistry(); - private Server fakeServer; - - @Before - public void setUp() throws Exception { - fakeServer = InProcessServerBuilder - .forName(serverName) - .fallbackHandlerRegistry(serviceRegistry) - .directExecutor() - .build() - .start(); - } - - @After - public void tearDown() throws Exception { - if (null != fakeServer) { - fakeServer.shutdown(); - } - } - - @Test - public void testBasic() { - ManagedChannel managedChannel = InProcessChannelBuilder.forName(serverName).directExecutor().build(); - Optional token = Optional.empty(); - StorageServerChannel channel = new StorageServerChannel(managedChannel, token); - assertNotNull(channel.getRootRangeService()); - assertNotNull(channel.getMetaRangeService()); - assertNotNull(channel.getStorageContainerService()); - assertNotNull(channel.getTableService()); - channel.close(); - } - - @Test - public void testIntercept() { - ManagedChannel channel = mock(ManagedChannel.class); - StorageServerChannel ssChannel = new StorageServerChannel(channel, Optional.empty()); - StorageServerChannel interceptedChannel = ssChannel.intercept(1L); - interceptedChannel.close(); - verify(channel, times(1)).shutdown(); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannelManager.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannelManager.java deleted file mode 100644 index 4b1a713b7fc..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/channel/TestStorageServerChannelManager.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.channel; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.junit.After; -import org.junit.Test; - -/** - * Unit test for {@link StorageServerChannelManager}. - */ -public class TestStorageServerChannelManager { - - private final Endpoint endpoint1 = Endpoint.newBuilder() - .setHostname("127.0.0.1") - .setPort(80) - .build(); - private final StorageServerChannel channel1 = mock(StorageServerChannel.class); - private final Endpoint endpoint2 = Endpoint.newBuilder() - .setHostname("127.0.0.2") - .setPort(8080) - .build(); - private final StorageServerChannel channel2 = mock(StorageServerChannel.class); - private final Endpoint endpoint3 = Endpoint.newBuilder() - .setHostname("127.0.0.3") - .setPort(8181) - .build(); - - private final StorageServerChannelManager channelManager = - new StorageServerChannelManager((endpoint) -> { - if (endpoint == endpoint1) { - return channel1; - } else if (endpoint == endpoint2) { - return channel2; - } else { - return mock(StorageServerChannel.class); - } - }); - - @After - public void tearDown() { - channelManager.close(); - } - - @Test - public void testGetNullChannel() { - assertNull(channelManager.getChannel(endpoint1)); - } - - @Test - public void testGetOrCreateChannel() { - StorageServerChannel channel = channelManager.getOrCreateChannel(endpoint1); - assertTrue(channel == channel1); - channel = channelManager.getOrCreateChannel(endpoint2); - assertTrue(channel == channel2); - channel = channelManager.getOrCreateChannel(endpoint3); - assertTrue(channel != channel1 && channel != channel2); - assertEquals(3, channelManager.getNumChannels()); - channelManager.close(); - assertEquals(0, channelManager.getNumChannels()); - verify(channel1, times(1)).close(); - verify(channel2, times(1)).close(); - verify(channel, times(1)).close(); - } - - @Test - public void testGetOrCreateChannelAfterClosed() { - channelManager.close(); - assertNull(channelManager.getOrCreateChannel(endpoint1)); - assertFalse(channelManager.contains(endpoint1)); - assertEquals(0, channelManager.getNumChannels()); - } - - @Test - public void testAddRangeServer() { - StorageServerChannel ch1 = mock(StorageServerChannel.class); - StorageServerChannel ch2 = mock(StorageServerChannel.class); - assertNull(channelManager.getChannel(endpoint1)); - assertTrue(channelManager.addStorageServer(endpoint1, ch1)); - assertTrue(ch1 == channelManager.getChannel(endpoint1)); - assertEquals(1, channelManager.getNumChannels()); - assertFalse(channelManager.addStorageServer(endpoint1, ch2)); - assertTrue(ch1 == channelManager.getChannel(endpoint1)); - assertEquals(1, channelManager.getNumChannels()); - verify(ch2, times(1)).close(); - } - - @Test - public void testAddRangeServerAfterClosed() { - channelManager.close(); - StorageServerChannel ch1 = mock(StorageServerChannel.class); - assertNull(channelManager.getChannel(endpoint1)); - assertFalse(channelManager.addStorageServer(endpoint1, ch1)); - assertNull(channelManager.getChannel(endpoint1)); - assertEquals(0, channelManager.getNumChannels()); - verify(ch1, times(1)).close(); - } - - @Test - public void testRemoveChannel() { - StorageServerChannel ch = mock(StorageServerChannel.class); - assertNull(channelManager.getChannel(endpoint1)); - assertTrue(channelManager.addStorageServer(endpoint1, ch)); - assertTrue(ch == channelManager.getChannel(endpoint1)); - assertEquals(1, channelManager.getNumChannels()); - assertTrue(ch == channelManager.removeChannel(endpoint1, null)); - verify(ch, times(1)).close(); - assertEquals(0, channelManager.getNumChannels()); - } - - @Test - public void testRemoveChannelAfterClosed() { - channelManager.close(); - assertNull(channelManager.removeChannel(endpoint1, null)); - } - - @Test - public void testConditionalRemoveChannelSuccess() { - StorageServerChannel ch1 = mock(StorageServerChannel.class); - assertNull(channelManager.getChannel(endpoint1)); - assertTrue(channelManager.addStorageServer(endpoint1, ch1)); - assertTrue(ch1 == channelManager.getChannel(endpoint1)); - assertEquals(1, channelManager.getNumChannels()); - assertTrue(ch1 == channelManager.removeChannel(endpoint1, ch1)); - verify(ch1, times(1)).close(); - assertEquals(0, channelManager.getNumChannels()); - } - - @Test - public void testConditionalRemoveChannelFailure() { - StorageServerChannel ch1 = mock(StorageServerChannel.class); - StorageServerChannel ch2 = mock(StorageServerChannel.class); - assertNull(channelManager.getChannel(endpoint1)); - assertTrue(channelManager.addStorageServer(endpoint1, ch1)); - assertTrue(ch1 == channelManager.getChannel(endpoint1)); - assertEquals(1, channelManager.getNumChannels()); - assertNull(channelManager.removeChannel(endpoint1, ch2)); - verify(ch1, times(0)).close(); - verify(ch2, times(0)).close(); - assertEquals(1, channelManager.getNumChannels()); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java deleted file mode 100644 index 56233354be2..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.container; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannelManager; -import org.apache.bookkeeper.clients.impl.internal.api.LocationClient; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.exceptions.ObjectClosedException; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint; -import org.junit.Test; - -/** - * Test Case for {@link StorageContainerChannel}. - */ -public class TestStorageContainerChannel extends GrpcClientTestBase { - - private OrderedScheduler scheduler; - private final LocationClient locationClient = mock(LocationClient.class); - - private StorageServerChannel mockChannel = newMockServerChannel(); - private StorageServerChannel mockChannel2 = newMockServerChannel(); - private StorageServerChannel mockChannel3 = newMockServerChannel(); - private final Endpoint endpoint = Endpoint.newBuilder() - .setHostname("127.0.0.1") - .setPort(8181) - .build(); - private final Endpoint endpoint2 = Endpoint.newBuilder() - .setHostname("127.0.0.2") - .setPort(8282) - .build(); - private final Endpoint endpoint3 = Endpoint.newBuilder() - .setHostname("127.0.0.3") - .setPort(8383) - .build(); - private final StorageServerChannelManager channelManager = new StorageServerChannelManager( - ep -> { - if (endpoint2 == ep) { - return mockChannel2; - } else if (endpoint3 == ep) { - return mockChannel3; - } else { - return mockChannel; - } - }); - - private StorageContainerChannel scClient; - - @Override - protected void doSetup() throws Exception { - scheduler = OrderedScheduler.newSchedulerBuilder() - .numThreads(1) - .name("test-range-server-manager") - .build(); - scClient = new StorageContainerChannel( - ROOT_STORAGE_CONTAINER_ID, - channelManager, - locationClient, - scheduler.chooseThread(ROOT_STORAGE_CONTAINER_ID)); - } - - @Override - protected void doTeardown() throws Exception { - if (null != scheduler) { - scheduler.shutdown(); - } - } - - private StorageServerChannel newMockServerChannel() { - StorageServerChannel channel = mock(StorageServerChannel.class); - when(channel.intercept(anyLong())).thenReturn(channel); - return channel; - } - - private void ensureCallbackExecuted() throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - scheduler.submit(() -> latch.countDown()); - latch.await(); - } - - @Test - public void testGetRootRangeServiceSuccess() throws Exception { - CompletableFuture> locateResponses = FutureUtils.createFuture(); - when(locationClient.locateStorageContainers(anyList())).thenReturn(locateResponses); - - // the future is not set before #getRootRangeService - assertNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - // call #getRootRangeService - CompletableFuture rsChannelFuture = scClient.getStorageContainerChannelFuture(); - // the future is set and the locationClient#locateStorageContainers is called - assertNotNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // if the request is outstanding, a second call will not call locationClient#locateStorageContainers - CompletableFuture rsChannelFuture1 = scClient.getStorageContainerChannelFuture(); - assertTrue(rsChannelFuture == rsChannelFuture1); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // prepare the result and complete the request - OneStorageContainerEndpointResponse oneResp = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(StatusCode.SUCCESS) - .setEndpoint( - StorageContainerEndpoint.newBuilder() - .setStorageContainerId(ROOT_STORAGE_CONTAINER_ID) - .setRevision(1000L) - .setRwEndpoint(endpoint) - .addRoEndpoint(endpoint) - .build()) - .build(); - locateResponses.complete(Lists.newArrayList(oneResp)); - // get the service - StorageServerChannel rsChannel = rsChannelFuture.get(); - assertTrue(rsChannel == mockChannel); - // verify storage container info - StorageContainerInfo scInfo = scClient.getStorageContainerInfo(); - assertEquals(ROOT_STORAGE_CONTAINER_ID, scInfo.getGroupId()); - assertEquals(1000L, scInfo.getRevision()); - assertEquals(endpoint, scInfo.getWriteEndpoint()); - assertEquals(Lists.newArrayList(endpoint, endpoint), scInfo.getReadEndpoints()); - // verify channel - assertEquals(mockChannel, channelManager.getChannel(endpoint)); - - verify(locationClient, times(1)).locateStorageContainers(anyList()); - } - - @Test - public void testGetRootRangeServiceFailureWhenClosingChannelManager() throws Exception { - CompletableFuture> locateResponses = FutureUtils.createFuture(); - when(locationClient.locateStorageContainers(anyList())).thenReturn(locateResponses); - - // the future is not set before #getRootRangeService - assertNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - // call #getRootRangeService - CompletableFuture rsChannelFuture = scClient.getStorageContainerChannelFuture(); - // the future is set and the locationClient#locateStorageContainers is called - assertNotNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // if the request is outstanding, a second call will not call locationClient#locateStorageContainers - CompletableFuture rsChannelFuture1 = scClient.getStorageContainerChannelFuture(); - assertTrue(rsChannelFuture == rsChannelFuture1); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // closing the channel manager - channelManager.close(); - // prepare the result and complete the request - OneStorageContainerEndpointResponse oneResp = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(StatusCode.SUCCESS) - .setEndpoint( - StorageContainerEndpoint.newBuilder() - .setStorageContainerId(ROOT_STORAGE_CONTAINER_ID) - .setRevision(1000L) - .setRwEndpoint(endpoint) - .addRoEndpoint(endpoint) - .build()) - .build(); - locateResponses.complete(Lists.newArrayList(oneResp)); - // verify the result - try { - rsChannelFuture.get(); - fail("Should fail get root range service if channel manager is shutting down."); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ObjectClosedException); - } - // verify storage container info - StorageContainerInfo scInfo = scClient.getStorageContainerInfo(); - assertEquals(ROOT_STORAGE_CONTAINER_ID, scInfo.getGroupId()); - assertEquals(1000L, scInfo.getRevision()); - assertEquals(endpoint, scInfo.getWriteEndpoint()); - assertEquals(Lists.newArrayList(endpoint, endpoint), scInfo.getReadEndpoints()); - // verify channel - assertNull(channelManager.getChannel(endpoint)); - - verify(locationClient, times(1)).locateStorageContainers(anyList()); - } - - @Test - public void testGetRootRangeServiceFailureOnStaleGroupInfo() throws Exception { - CompletableFuture> locateResponses1 = FutureUtils.createFuture(); - CompletableFuture> locateResponses2 = FutureUtils.createFuture(); - CompletableFuture> locateResponses3 = FutureUtils.createFuture(); - when(locationClient.locateStorageContainers(anyList())) - .thenReturn(locateResponses1) - .thenReturn(locateResponses3); - - // the future is not set before #getRootRangeService - assertNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - // call #getRootRangeService - CompletableFuture rsChannelFuture = scClient.getStorageContainerChannelFuture(); - // the future is set and the locationClient#locateStorageContainers is called - assertNotNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // if the request is outstanding, a second call will not call locationClient#locateStorageContainers - CompletableFuture rsChannelFuture1 = scClient.getStorageContainerChannelFuture(); - assertTrue(rsChannelFuture == rsChannelFuture1); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - - // - // Complete the first response - // - - // prepare the result and complete the request - OneStorageContainerEndpointResponse oneResp1 = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(StatusCode.SUCCESS) - .setEndpoint( - StorageContainerEndpoint.newBuilder() - .setStorageContainerId(ROOT_STORAGE_CONTAINER_ID) - .setRevision(1000L) - .setRwEndpoint(endpoint) - .addRoEndpoint(endpoint) - .build()) - .build(); - locateResponses1.complete(Lists.newArrayList(oneResp1)); - // get the service - StorageServerChannel rsChannel = rsChannelFuture.get(); - assertTrue(rsChannel == mockChannel); - // verify storage container info - StorageContainerInfo scInfo = scClient.getStorageContainerInfo(); - assertEquals(ROOT_STORAGE_CONTAINER_ID, scInfo.getGroupId()); - assertEquals(1000L, scInfo.getRevision()); - assertEquals(endpoint, scInfo.getWriteEndpoint()); - assertEquals(Lists.newArrayList(endpoint, endpoint), scInfo.getReadEndpoints()); - // verify channel - assertEquals(mockChannel, channelManager.getChannel(endpoint)); - - // - // Reset and complete the second response - // - - scClient.resetStorageServerChannelFuture(); - rsChannelFuture = scClient.getStorageContainerChannelFuture(); - - OneStorageContainerEndpointResponse oneResp2 = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(StatusCode.SUCCESS) - .setEndpoint( - StorageContainerEndpoint.newBuilder() - .setStorageContainerId(ROOT_STORAGE_CONTAINER_ID) - .setRevision(999L) - .setRwEndpoint(endpoint2) - .addRoEndpoint(endpoint2) - .build()) - .build(); - locateResponses2.complete(Lists.newArrayList(oneResp2)); - ensureCallbackExecuted(); - - // verify storage container info : group info will not be updated - scInfo = scClient.getStorageContainerInfo(); - assertEquals(ROOT_STORAGE_CONTAINER_ID, scInfo.getGroupId()); - assertEquals(1000L, scInfo.getRevision()); - assertEquals(endpoint, scInfo.getWriteEndpoint()); - assertEquals(Lists.newArrayList(endpoint, endpoint), scInfo.getReadEndpoints()); - // the future will not be completed - assertFalse(rsChannelFuture.isDone()); - - // - // complete the third response - // - - scClient.resetStorageServerChannelFuture(); - rsChannelFuture = scClient.getStorageContainerChannelFuture(); - - OneStorageContainerEndpointResponse oneResp3 = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(StatusCode.SUCCESS) - .setEndpoint( - StorageContainerEndpoint.newBuilder() - .setStorageContainerId(ROOT_STORAGE_CONTAINER_ID) - .setRevision(1001L) - .setRwEndpoint(endpoint3) - .addRoEndpoint(endpoint3) - .build()) - .build(); - locateResponses3.complete(Lists.newArrayList(oneResp3)); - ensureCallbackExecuted(); - - StorageServerChannel rsChannel3 = rsChannelFuture.get(); - assertTrue(rsChannel3 == mockChannel3); - // verify storage container info : group info will not be updated - scInfo = scClient.getStorageContainerInfo(); - assertEquals(ROOT_STORAGE_CONTAINER_ID, scInfo.getGroupId()); - assertEquals(1001L, scInfo.getRevision()); - assertEquals(endpoint3, scInfo.getWriteEndpoint()); - assertEquals(Lists.newArrayList(endpoint3, endpoint3), scInfo.getReadEndpoints()); - - verify(locationClient, times(3)).locateStorageContainers(anyList()); - } - - @Test - public void testGetRootRangeServiceUnexpectedException() throws Exception { - CompletableFuture> locateResponses1 = FutureUtils.createFuture(); - CompletableFuture> locateResponses2 = FutureUtils.createFuture(); - when(locationClient.locateStorageContainers(anyList())) - .thenReturn(locateResponses1) - .thenReturn(locateResponses2); - - // the future is not set before #getRootRangeService - assertNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - // call #getRootRangeService - CompletableFuture rsChannelFuture = scClient.getStorageContainerChannelFuture(); - // the future is set and the locationClient#locateStorageContainers is called - assertNotNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // if the request is outstanding, a second call will not call locationClient#locateStorageContainers - CompletableFuture rsChannelFuture1 = scClient.getStorageContainerChannelFuture(); - assertTrue(rsChannelFuture == rsChannelFuture1); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // prepare the result and complete the request - OneStorageContainerEndpointResponse oneResp = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(StatusCode.SUCCESS) - .setEndpoint( - StorageContainerEndpoint.newBuilder() - .setStorageContainerId(ROOT_STORAGE_CONTAINER_ID) - .setRevision(1000L) - .setRwEndpoint(endpoint) - .addRoEndpoint(endpoint) - .build()) - .build(); - // complete with wrong responses - locateResponses1.complete(Lists.newArrayList(oneResp, oneResp)); - ensureCallbackExecuted(); - // verify channel - assertNull(channelManager.getChannel(endpoint)); - // verify storage container info - assertNull(scClient.getStorageContainerInfo()); - - // complete with right responses - locateResponses2.complete(Lists.newArrayList(oneResp)); - - // get the service - StorageServerChannel rsChannel = rsChannelFuture.get(); - assertTrue(rsChannel == mockChannel); - // verify storage container info - StorageContainerInfo scInfo = scClient.getStorageContainerInfo(); - assertEquals(ROOT_STORAGE_CONTAINER_ID, scInfo.getGroupId()); - assertEquals(1000L, scInfo.getRevision()); - assertEquals(endpoint, scInfo.getWriteEndpoint()); - assertEquals(Lists.newArrayList(endpoint, endpoint), scInfo.getReadEndpoints()); - // verify channel - assertEquals(mockChannel, channelManager.getChannel(endpoint)); - - verify(locationClient, times(2)).locateStorageContainers(anyList()); - } - - @Test - public void testGetRootRangeServiceExceptionally() throws Exception { - CompletableFuture> locateResponses1 = FutureUtils.createFuture(); - CompletableFuture> locateResponses2 = FutureUtils.createFuture(); - when(locationClient.locateStorageContainers(anyList())) - .thenReturn(locateResponses1) - .thenReturn(locateResponses2); - - // the future is not set before #getRootRangeService - assertNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - // call #getRootRangeService - CompletableFuture rsChannelFuture = scClient.getStorageContainerChannelFuture(); - // the future is set and the locationClient#locateStorageContainers is called - assertNotNull(scClient.getStorageServerChannelFuture()); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // if the request is outstanding, a second call will not call locationClient#locateStorageContainers - CompletableFuture rsChannelFuture1 = scClient.getStorageContainerChannelFuture(); - assertTrue(rsChannelFuture == rsChannelFuture1); - assertNull(scClient.getStorageContainerInfo()); - verify(locationClient, times(1)).locateStorageContainers(anyList()); - // prepare the result and complete the request - OneStorageContainerEndpointResponse oneResp = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(StatusCode.SUCCESS) - .setEndpoint( - StorageContainerEndpoint.newBuilder() - .setStorageContainerId(ROOT_STORAGE_CONTAINER_ID) - .setRevision(1000L) - .setRwEndpoint(endpoint) - .addRoEndpoint(endpoint) - .build()) - .build(); - // complete exceptionally - locateResponses1.completeExceptionally(new ClientException("test-exception")); - ensureCallbackExecuted(); - // verify channel - assertNull(channelManager.getChannel(endpoint)); - // verify storage container info - assertNull(scClient.getStorageContainerInfo()); - - // complete with right responses - locateResponses2.complete(Lists.newArrayList(oneResp)); - - // get the service - StorageServerChannel rsChannel = rsChannelFuture.get(); - assertTrue(rsChannel == mockChannel); - // verify storage container info - StorageContainerInfo scInfo = scClient.getStorageContainerInfo(); - assertEquals(ROOT_STORAGE_CONTAINER_ID, scInfo.getGroupId()); - assertEquals(1000L, scInfo.getRevision()); - assertEquals(endpoint, scInfo.getWriteEndpoint()); - assertEquals(Lists.newArrayList(endpoint, endpoint), scInfo.getReadEndpoints()); - // verify channel - assertEquals(mockChannel, channelManager.getChannel(endpoint)); - - verify(locationClient, times(2)).locateStorageContainers(anyList()); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannelManager.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannelManager.java deleted file mode 100644 index 20750daf00f..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannelManager.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.container; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Test; - -/** - * Unit tests for {@link StorageContainerChannelManager}. - */ -public class TestStorageContainerChannelManager { - - @Test - public void testGetOrCreate() { - StorageContainerChannel channel1 = mock(StorageContainerChannel.class); - StorageContainerChannel channel2 = mock(StorageContainerChannel.class); - StorageContainerChannel channel3 = mock(StorageContainerChannel.class); - - StorageContainerChannelFactory factory = mock(StorageContainerChannelFactory.class); - StorageContainerChannelManager manager = new StorageContainerChannelManager(factory); - when(factory.createStorageContainerChannel(anyLong())) - .thenReturn(channel1) - .thenReturn(channel2) - .thenReturn(channel3); - - assertNull(manager.remove(1L)); - assertEquals(channel1, manager.getOrCreate(1L)); - verify(factory, times(1)).createStorageContainerChannel(eq(1L)); - assertEquals(channel1, manager.getOrCreate(1L)); - verify(factory, times(1)).createStorageContainerChannel(eq(1L)); - - assertEquals(channel1, manager.remove(1L)); - } - - @Test - public void testClear() throws Exception { - StorageContainerChannelManager manager = new StorageContainerChannelManager( - scId -> mock(StorageContainerChannel.class)); - - int numChannels = 10; - for (int i = 0; i < numChannels; i++) { - assertNotNull(manager.getOrCreate(i)); - } - assertEquals(numChannels, manager.getNumChannels()); - manager.close(); - assertEquals(0, manager.getNumChannels()); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerInfo.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerInfo.java deleted file mode 100644 index ce0dc3650b4..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerInfo.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.container; - -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Lists; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.junit.Test; - -/** - * Unit test for {@link StorageContainerInfo}. - */ -public class TestStorageContainerInfo { - - @Test - public void testBasic() { - long groupId = 1234L; - long revision = 4468L; - Endpoint endpoint = Endpoint.newBuilder() - .setHostname("123.46.78.96") - .setPort(3181) - .build(); - StorageContainerInfo sc = StorageContainerInfo.of( - groupId, - revision, - endpoint, - Lists.newArrayList(endpoint)); - assertEquals("Group ID mismatch", groupId, sc.getGroupId()); - assertEquals("Revision mismatch", revision, sc.getRevision()); - assertEquals("Write Endpoint mismatch", endpoint, sc.getWriteEndpoint()); - assertEquals("Read Endpoint mismatch", Lists.newArrayList(endpoint), sc.getReadEndpoints()); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerManager.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerManager.java deleted file mode 100644 index a11f4f2c931..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerManager.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.container; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.junit.Test; - -/** - * Unit test for {@link StorageContainerManager}. - */ -public class TestStorageContainerManager { - - private final StorageContainerManager manager = new StorageContainerManager(); - private final Endpoint endpoint1 = Endpoint.newBuilder() - .setHostname("128.0.0.1") - .setPort(3181) - .build(); - private final Endpoint endpoint2 = Endpoint.newBuilder() - .setHostname("128.0.0.1") - .setPort(3181) - .build(); - - @Test - public void testGetNullStorageContainer() { - assertNull(manager.getStorageContainer(1234L)); - } - - @Test - public void testAddStorageContainer() { - long groupId = 1234L; - long revision = 5678L; - StorageContainerInfo sc1 = StorageContainerInfo.of( - groupId, - revision, - endpoint1); - assertNull(manager.getStorageContainer(groupId)); - assertTrue(manager.replaceStorageContainer(groupId, sc1)); - assertTrue(sc1 == manager.getStorageContainer(groupId)); - } - - @Test - public void testReplaceStorageContainerWithNewerRevision() { - long groupId = 1234L; - long revision1 = 5678L; - long revision2 = 5679L; - StorageContainerInfo sc1 = StorageContainerInfo.of( - groupId, - revision1, - endpoint1); - StorageContainerInfo sc2 = StorageContainerInfo.of( - groupId, - revision2, - endpoint2); - assertNull(manager.getStorageContainer(groupId)); - assertTrue(manager.replaceStorageContainer(groupId, sc1)); - assertTrue(sc1 == manager.getStorageContainer(groupId)); - assertTrue(manager.replaceStorageContainer(groupId, sc2)); - assertTrue(sc2 == manager.getStorageContainer(groupId)); - } - - @Test - public void testReplaceStorageContainerWithOlderRevision() { - long groupId = 1234L; - long revision1 = 5678L; - long revision2 = 5679L; - StorageContainerInfo sc1 = StorageContainerInfo.of( - groupId, - revision1, - endpoint1); - StorageContainerInfo sc2 = StorageContainerInfo.of( - groupId, - revision2, - endpoint2); - assertNull(manager.getStorageContainer(groupId)); - assertTrue(manager.replaceStorageContainer(groupId, sc2)); - assertTrue(sc2 == manager.getStorageContainer(groupId)); - assertFalse(manager.replaceStorageContainer(groupId, sc1)); - assertTrue(sc2 == manager.getStorageContainer(groupId)); - } - - @Test - public void testRemoveStorageContainer() { - long groupId = 1234L; - long revision = 5678L; - StorageContainerInfo sc1 = StorageContainerInfo.of( - groupId, - revision, - endpoint1); - assertNull(manager.getStorageContainer(groupId)); - assertTrue(manager.replaceStorageContainer(groupId, sc1)); - assertTrue(sc1 == manager.getStorageContainer(groupId)); - manager.removeStorageContainer(groupId); - assertNull(manager.getStorageContainer(groupId)); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java deleted file mode 100644 index c61052c48f8..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.clients.impl.internal.ProtocolInternalUtils.createRootRangeException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import io.grpc.inprocess.InProcessChannelBuilder; -import java.io.IOException; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import lombok.Cleanup; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.InvalidNamespaceNameException; -import org.apache.bookkeeper.clients.exceptions.NamespaceExistsException; -import org.apache.bookkeeper.clients.exceptions.NamespaceNotFoundException; -import org.apache.bookkeeper.clients.exceptions.StreamExistsException; -import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannelManager; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannelManager; -import org.apache.bookkeeper.clients.impl.internal.api.LocationClient; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * The Test Base of {@link RootRangeClientImpl}. - */ -public abstract class RootRangeClientImplTestBase extends GrpcClientTestBase { - - @Rule - public final TestName testName = new TestName(); - - private OrderedScheduler scheduler; - private RootRangeClientImpl rootRangeClient; - private final LocationClient locationClient = mock(LocationClient.class); - - private StorageServerChannel mockChannel = mock(StorageServerChannel.class); - private StorageServerChannel mockChannel2 = mock(StorageServerChannel.class); - private StorageServerChannel mockChannel3 = mock(StorageServerChannel.class); - private final Endpoint endpoint = Endpoint.newBuilder() - .setHostname("127.0.0.1") - .setPort(8181) - .build(); - private final Endpoint endpoint2 = Endpoint.newBuilder() - .setHostname("127.0.0.2") - .setPort(8282) - .build(); - private final Endpoint endpoint3 = Endpoint.newBuilder() - .setHostname("127.0.0.3") - .setPort(8383) - .build(); - private final StorageServerChannelManager channelManager = new StorageServerChannelManager( - ep -> { - if (endpoint2 == ep) { - return mockChannel2; - } else if (endpoint3 == ep) { - return mockChannel3; - } else { - return mockChannel; - } - }); - - @Override - protected void doSetup() throws Exception { - scheduler = OrderedScheduler.newSchedulerBuilder() - .numThreads(1) - .name("test-range-server-manager") - .build(); - rootRangeClient = new RootRangeClientImpl( - scheduler, - new StorageContainerChannelManager( - channelManager, - locationClient, - scheduler)); - } - - @Override - protected void doTeardown() throws Exception { - if (null != scheduler) { - scheduler.shutdown(); - } - } - - protected abstract RootRangeServiceImplBase createRootRangeServiceForSuccess(); - - protected abstract void verifySuccess(RootRangeClient rootRangeClient) throws Exception; - - @Test - public void testRequestSuccess() throws Exception { - CompletableFuture serviceFuture = FutureUtils.createFuture(); - rootRangeClient.getStorageContainerClient().setStorageServerChannelFuture(serviceFuture); - - RootRangeServiceImplBase rootRangeService = createRootRangeServiceForSuccess(); - serviceRegistry.addService(rootRangeService.bindService()); - @Cleanup StorageServerChannel rsChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serviceFuture.complete(rsChannel); - - verifySuccess(rootRangeClient); - } - - - protected abstract RootRangeServiceImplBase createRootRangeServiceForRequestFailure(); - - protected abstract void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception; - - @Test - public void testRequestFailure() throws Exception { - CompletableFuture serviceFuture = FutureUtils.createFuture(); - rootRangeClient.getStorageContainerClient().setStorageServerChannelFuture(serviceFuture); - - RootRangeServiceImplBase rootRangeService = createRootRangeServiceForRequestFailure(); - serviceRegistry.addService(rootRangeService.bindService()); - @Cleanup StorageServerChannel rsChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serviceFuture.complete(rsChannel); - - verifyRequestFailure(rootRangeClient); - } - - - protected abstract RootRangeServiceImplBase createRootRangeServiceForRpcFailure(); - - protected abstract void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception; - - @Test - public void testRpcFailure() throws Exception { - CompletableFuture serviceFuture = FutureUtils.createFuture(); - rootRangeClient.getStorageContainerClient().setStorageServerChannelFuture(serviceFuture); - - RootRangeServiceImplBase rootRangeService = createRootRangeServiceForRpcFailure(); - serviceRegistry.addService(rootRangeService.bindService()); - @Cleanup StorageServerChannel rsChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serviceFuture.complete(rsChannel); - - verifyRpcFailure(rootRangeClient); - } - - protected abstract void verifyChannelFailure(IOException expectedException, RootRangeClient rootRangeClient) - throws Exception; - - @Test - public void testChannelFailure() throws Exception { - CompletableFuture serviceFuture = FutureUtils.createFuture(); - rootRangeClient.getStorageContainerClient().setStorageServerChannelFuture(serviceFuture); - - IOException ioe = new IOException(testName.getMethodName()); - serviceFuture.completeExceptionally(ioe); - - verifyChannelFailure(ioe, rootRangeClient); - } - - @Test - public void testCreateRootRangeException() { - String name = "test-create-root-range-exception"; - // stream exists exception - Throwable cause1 = createRootRangeException(name, StatusCode.STREAM_EXISTS); - assertTrue(cause1 instanceof StreamExistsException); - StreamExistsException see = (StreamExistsException) cause1; - // stream not found - Throwable cause2 = createRootRangeException(name, StatusCode.STREAM_NOT_FOUND); - assertTrue(cause2 instanceof StreamNotFoundException); - StreamNotFoundException snfe = (StreamNotFoundException) cause2; - // failure - Throwable cause3 = createRootRangeException(name, StatusCode.FAILURE); - assertTrue(cause3 instanceof ClientException); - ClientException se = (ClientException) cause3; - assertEquals("fail to access its root range : code = " + StatusCode.FAILURE, - se.getMessage()); - // unexpected - Throwable cause4 = createRootRangeException(name, StatusCode.BAD_VERSION); - assertTrue(cause4 instanceof ClientException); - // namespace exists exception - Throwable cause5 = createRootRangeException(name, StatusCode.NAMESPACE_EXISTS); - assertTrue(cause5 instanceof NamespaceExistsException); - // namespace not-found exception - Throwable cause6 = createRootRangeException(name, StatusCode.NAMESPACE_NOT_FOUND); - assertTrue(cause6 instanceof NamespaceNotFoundException); - // invalid namespace name - Throwable cause7 = createRootRangeException(name, StatusCode.INVALID_NAMESPACE_NAME); - assertTrue(cause7 instanceof InvalidNamespaceNameException); - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplWithRetriesTest.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplWithRetriesTest.java deleted file mode 100644 index fa160028490..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplWithRetriesTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.impl.internal; - -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.Backoff; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link RootRangeClientImplWithRetries}. - */ -public class RootRangeClientImplWithRetriesTest { - - private static final int NUM_RETRIES = 3; - - private static final String NS_NAME = "test-namespace"; - private static final NamespaceConfiguration NS_CONF = NamespaceConfiguration.newBuilder().build(); - private static final NamespaceProperties NS_PROPS = NamespaceProperties.newBuilder().build(); - private static final String STREAM_NAME = "test-stream"; - private static final StreamConfiguration STREAM_CONF = StreamConfiguration.newBuilder().build(); - private static final StreamProperties STREAM_PROPS = StreamProperties.newBuilder().build(); - - private AtomicInteger callCounter; - private RootRangeClient client; - private OrderedScheduler scheduler; - private RootRangeClientImplWithRetries clientWithRetries; - - @Before - public void setup() { - this.callCounter = new AtomicInteger(NUM_RETRIES); - this.client = mock(RootRangeClient.class); - this.scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduler") - .numThreads(1) - .build(); - this.clientWithRetries = new RootRangeClientImplWithRetries( - client, - Backoff.Constant.of(10, NUM_RETRIES), - scheduler); - } - - @Test - public void testCreateNamespace() throws Exception { - when(client.createNamespace(anyString(), any(NamespaceConfiguration.class))) - .thenAnswer(invocationOnMock -> { - if (callCounter.decrementAndGet() > 0) { - return FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)); - } else { - return FutureUtils.value(NS_PROPS); - } - }); - - assertSame(NS_PROPS, FutureUtils.result(clientWithRetries.createNamespace(NS_NAME, NS_CONF))); - } - - @Test - public void testDeleteNamespace() throws Exception { - when(client.deleteNamespace(anyString())) - .thenAnswer(invocationOnMock -> { - if (callCounter.decrementAndGet() > 0) { - return FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)); - } else { - return FutureUtils.value(true); - } - }); - - assertTrue(FutureUtils.result(clientWithRetries.deleteNamespace(NS_NAME))); - } - - @Test - public void testGetNamespace() throws Exception { - when(client.getNamespace(anyString())) - .thenAnswer(invocationOnMock -> { - if (callCounter.decrementAndGet() > 0) { - return FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)); - } else { - return FutureUtils.value(NS_PROPS); - } - }); - - assertSame(NS_PROPS, FutureUtils.result(clientWithRetries.getNamespace(NS_NAME))); - } - - @Test - public void testCreateStream() throws Exception { - when(client.createStream(anyString(), anyString(), any(StreamConfiguration.class))) - .thenAnswer(invocationOnMock -> { - if (callCounter.decrementAndGet() > 0) { - return FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)); - } else { - return FutureUtils.value(STREAM_PROPS); - } - }); - - assertSame(STREAM_PROPS, FutureUtils.result(clientWithRetries.createStream(NS_NAME, STREAM_NAME, STREAM_CONF))); - } - - @Test - public void testDeleteStream() throws Exception { - when(client.deleteStream(anyString(), anyString())) - .thenAnswer(invocationOnMock -> { - if (callCounter.decrementAndGet() > 0) { - return FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)); - } else { - return FutureUtils.value(true); - } - }); - - assertTrue(FutureUtils.result(clientWithRetries.deleteStream(NS_NAME, STREAM_NAME))); - } - - @Test - public void testGetStream() throws Exception { - when(client.getStream(anyString(), anyString())) - .thenAnswer(invocationOnMock -> { - if (callCounter.decrementAndGet() > 0) { - return FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)); - } else { - return FutureUtils.value(STREAM_PROPS); - } - }); - - assertSame(STREAM_PROPS, FutureUtils.result(clientWithRetries.getStream(NS_NAME, STREAM_NAME))); - } - - @Test - public void testGetStreamById() throws Exception { - when(client.getStream(anyLong())) - .thenAnswer(invocationOnMock -> { - if (callCounter.decrementAndGet() > 0) { - return FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)); - } else { - return FutureUtils.value(STREAM_PROPS); - } - }); - - assertSame(STREAM_PROPS, FutureUtils.result(clientWithRetries.getStream(1234L))); - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java deleted file mode 100644 index 665b8ac925e..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.clients.impl.internal.LocationClientImpl.LOCATE_STORAGE_CONTAINERS_RETRY_PREDICATE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import io.grpc.ServerServiceDefinition; -import io.grpc.Status; -import io.grpc.StatusException; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.StorageContainerException; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.utils.NetUtils; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.IRevisioned; -import org.apache.bookkeeper.common.util.Revisioned; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerServiceGrpc.StorageContainerServiceImplBase; -import org.junit.Test; - -/** - * Unit test for {@link LocationClientImpl}. - */ -@Slf4j -public class TestLocationClientImpl extends GrpcClientTestBase { - - private static StorageContainerEndpoint createEndpoint(int groupId) { - return StorageContainerEndpoint.newBuilder() - .setStorageContainerId(groupId) - .setRevision(1000L + groupId) - .setRwEndpoint(NetUtils.createEndpoint("127.0.0." + groupId, groupId)) - .addRoEndpoint(NetUtils.createEndpoint("128.0.0." + groupId, groupId)) - .build(); - } - - private LocationClientImpl locationClient; - - private final List endpoints = IntStream - .range(0, 10) - .boxed() - .map(i -> createEndpoint(i)) - .collect(Collectors.toList()); - - private final StorageContainerServiceImplBase locationService = new StorageContainerServiceImplBase() { - - @Override - public void getStorageContainerEndpoint(GetStorageContainerEndpointRequest request, - StreamObserver responseObserver) { - GetStorageContainerEndpointResponse.Builder respBuilder = GetStorageContainerEndpointResponse.newBuilder(); - if (0 == request.getRequestsCount()) { - responseObserver.onError(new StatusRuntimeException(Status.INVALID_ARGUMENT)); - } else { - for (OneStorageContainerEndpointRequest oneRequest : request.getRequestsList()) { - respBuilder.addResponses(processOneStorageContainerEndpointRequest(oneRequest)); - } - respBuilder.setStatusCode(StatusCode.SUCCESS); - responseObserver.onNext(respBuilder.build()); - } - responseObserver.onCompleted(); - } - - OneStorageContainerEndpointResponse.Builder processOneStorageContainerEndpointRequest( - OneStorageContainerEndpointRequest request) { - StatusCode code; - StorageContainerEndpoint endpoint = null; - if (request.getStorageContainer() < 0) { - code = StatusCode.INVALID_GROUP_ID; - } else if (request.getStorageContainer() >= endpoints.size()) { - code = StatusCode.GROUP_NOT_FOUND; - } else { - code = StatusCode.SUCCESS; - endpoint = endpoints.get((int) request.getStorageContainer()); - } - if (endpoint != null) { - if (endpoint.getRevision() <= request.getRevision()) { - code = StatusCode.STALE_GROUP_INFO; - endpoint = null; - } - } - OneStorageContainerEndpointResponse.Builder builder = OneStorageContainerEndpointResponse.newBuilder() - .setStatusCode(code); - if (null != endpoint) { - builder = builder.setEndpoint(endpoint); - } - return builder; - } - }; - private ServerServiceDefinition locationServiceDefinition; - - @Override - protected void doSetup() throws Exception { - StorageClientSettings settings = - StorageClientSettings.newBuilder() - .serviceUri("bk+inprocess://" + serverName) - .build(); - locationClient = new LocationClientImpl(settings, scheduler); - locationServiceDefinition = locationService.bindService(); - serviceRegistry.addService(locationServiceDefinition); - } - - @Override - protected void doTeardown() throws Exception { - if (null != locationClient) { - locationClient.close(); - } - } - - private void assertOneStorageContainerEndpointResponse( - OneStorageContainerEndpointResponse response, - StatusCode expectedStatusCode, - StorageContainerEndpoint expectedEndpoint) { - assertEquals(expectedStatusCode, response.getStatusCode()); - if (null != expectedEndpoint) { - assertEquals("Expected endpoint = " + expectedEndpoint + ", Actual endpoint = " + response.getEndpoint(), - expectedEndpoint, response.getEndpoint()); - } else { - assertFalse(response.hasEndpoint()); - } - } - - @Test - public void testLocateStorageContainersSuccess() throws Exception { - CompletableFuture> future = - locationClient.locateStorageContainers(Lists.newArrayList( - Revisioned.of(1L, IRevisioned.ANY_REVISION), - Revisioned.of(3L, IRevisioned.ANY_REVISION), - Revisioned.of(5L, IRevisioned.ANY_REVISION), - Revisioned.of(7L, IRevisioned.ANY_REVISION) - )); - List result = FutureUtils.result(future); - assertEquals(4, result.size()); - assertOneStorageContainerEndpointResponse(result.get(0), StatusCode.SUCCESS, endpoints.get(1)); - assertOneStorageContainerEndpointResponse(result.get(1), StatusCode.SUCCESS, endpoints.get(3)); - assertOneStorageContainerEndpointResponse(result.get(2), StatusCode.SUCCESS, endpoints.get(5)); - assertOneStorageContainerEndpointResponse(result.get(3), StatusCode.SUCCESS, endpoints.get(7)); - } - - @Test - public void testLocateStorageContainersInvalidArgs() throws Exception { - CompletableFuture> future = - locationClient.locateStorageContainers(Lists.newArrayList()); - try { - future.get(); - fail("Should fail with invalid arguments"); - } catch (ExecutionException ee) { - Throwable cause = ee.getCause(); - assertTrue( - "Unexpected exception : " + cause, - cause instanceof StatusRuntimeException); - assertEquals(Status.INVALID_ARGUMENT, ((StatusRuntimeException) cause).getStatus()); - } - } - - @Test - public void testLocateStorageContainersFailures() throws Exception { - CompletableFuture> future = - locationClient.locateStorageContainers(Lists.newArrayList( - Revisioned.of(-1L, IRevisioned.ANY_REVISION), // invalid group id - Revisioned.of(1L, IRevisioned.ANY_REVISION), // valid group id - Revisioned.of(3L, Long.MAX_VALUE), // stale revision - Revisioned.of(Long.MAX_VALUE, IRevisioned.ANY_REVISION) // not found - )); - List result = FutureUtils.result(future); - assertEquals(4, result.size()); - assertOneStorageContainerEndpointResponse(result.get(0), StatusCode.INVALID_GROUP_ID, null); - assertOneStorageContainerEndpointResponse(result.get(1), StatusCode.SUCCESS, endpoints.get(1)); - assertOneStorageContainerEndpointResponse(result.get(2), StatusCode.STALE_GROUP_INFO, null); - assertOneStorageContainerEndpointResponse(result.get(3), StatusCode.GROUP_NOT_FOUND, null); - } - - @Test - public void testLocateStorageContainersRetryPredicate() throws Exception { - assertTrue(LOCATE_STORAGE_CONTAINERS_RETRY_PREDICATE.test( - new StatusException(Status.INTERNAL))); - assertTrue(LOCATE_STORAGE_CONTAINERS_RETRY_PREDICATE.test( - new StatusRuntimeException(Status.INTERNAL))); - assertFalse(LOCATE_STORAGE_CONTAINERS_RETRY_PREDICATE.test( - new StatusException(Status.INVALID_ARGUMENT))); - assertFalse(LOCATE_STORAGE_CONTAINERS_RETRY_PREDICATE.test( - new StatusRuntimeException(Status.INVALID_ARGUMENT))); - assertTrue(LOCATE_STORAGE_CONTAINERS_RETRY_PREDICATE.test( - new ClientException("test-2"))); - assertTrue(LOCATE_STORAGE_CONTAINERS_RETRY_PREDICATE.test( - new StorageContainerException(StatusCode.FAILURE, "test-3"))); - } - - @Test - public void testLocateStorageContainersSucceedAfterRetried() throws Exception { - serviceRegistry.removeService(locationServiceDefinition); - final AtomicInteger retries = new AtomicInteger(3); - StatusRuntimeException statusException = new StatusRuntimeException(Status.INTERNAL); - StorageContainerServiceImplBase locationServiceWithFailures = - new StorageContainerServiceImplBase() { - @Override - public void getStorageContainerEndpoint( - GetStorageContainerEndpointRequest request, - StreamObserver responseObserver) { - if (retries.decrementAndGet() == 0) { - locationService.getStorageContainerEndpoint(request, responseObserver); - return; - } - responseObserver.onError(statusException); - } - }; - serviceRegistry.addService(locationServiceWithFailures.bindService()); - testLocateStorageContainersSuccess(); - assertEquals(0, retries.get()); - } - - @Test - public void testLocateStorageContainersFailureAfterRetried() throws Exception { - serviceRegistry.removeService(locationServiceDefinition); - final AtomicInteger retries = new AtomicInteger(3); - StatusRuntimeException statusException = new StatusRuntimeException(Status.INTERNAL); - StorageContainerServiceImplBase locationServiceWithFailures = - new StorageContainerServiceImplBase() { - @Override - public void getStorageContainerEndpoint( - GetStorageContainerEndpointRequest request, - StreamObserver responseObserver) { - if (retries.decrementAndGet() == 0) { - responseObserver.onError(new StatusRuntimeException(Status.INVALID_ARGUMENT)); - return; - } - responseObserver.onError(statusException); - } - }; - serviceRegistry.addService(locationServiceWithFailures.bindService()); - CompletableFuture> future = - locationClient.locateStorageContainers(Lists.newArrayList( - Revisioned.of(1L, IRevisioned.ANY_REVISION) - )); - try { - future.get(); - fail("should fail with exception"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - assertEquals(Status.INVALID_ARGUMENT, ((StatusRuntimeException) ee.getCause()).getStatus()); - } - assertEquals(0, retries.get()); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java deleted file mode 100644 index 985b9551576..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.clients.impl.internal.ProtocolInternalUtils.createActiveRanges; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import com.google.common.collect.Lists; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import lombok.Cleanup; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannelManager; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannelManager; -import org.apache.bookkeeper.clients.impl.internal.api.HashStreamRanges; -import org.apache.bookkeeper.clients.impl.internal.api.LocationClient; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stream.proto.RangeProperties; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse; -import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.RelatedRanges; -import org.apache.bookkeeper.stream.proto.storage.RelationType; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Test Case for {@link MetaRangeClientImpl}. - */ -public class TestMetaRangeClientImpl extends GrpcClientTestBase { - - private static final long streamId = 1234L; - private static final long groupId = 456L; - private static final StreamProperties streamProps = StreamProperties.newBuilder() - .setStreamId(streamId) - .setStorageContainerId(groupId) - .setStreamName("test-meta-range-client") - .setStreamConf(StreamConfiguration.newBuilder().build()) - .build(); - private final LocationClient locationClient = mock(LocationClient.class); - private MetaRangeClientImpl metaRangeClient; - private final StorageServerChannel rsChannel = mock(StorageServerChannel.class); - private final StorageServerChannelManager channelManager = new StorageServerChannelManager( - ep -> rsChannel); - - @Override - protected void doSetup() throws Exception { - scheduler = OrderedScheduler.newSchedulerBuilder() - .numThreads(1) - .name("test-meta-range-client") - .build(); - metaRangeClient = new MetaRangeClientImpl( - streamProps, - scheduler, - new StorageContainerChannelManager( - channelManager, - locationClient, - scheduler)); - } - - @Override - protected void doTeardown() throws Exception { - if (null != scheduler) { - scheduler.shutdown(); - } - } - - - private RelatedRanges buildRelatedRange(long startKey, - long endKey, - long rangeId, - long groupId, - List parentRanges) { - return RelatedRanges.newBuilder() - .setProps(buildRangeMeta( - startKey, endKey, rangeId, groupId)) - .setType(RelationType.PARENTS) - .addAllRelatedRanges(parentRanges) - .build(); - } - - - private RangeProperties buildRangeMeta(long startKey, - long endKey, - long rangeId, - long groupId) { - return RangeProperties.newBuilder() - .setStartHashKey(startKey) - .setEndHashKey(endKey) - .setRangeId(rangeId) - .setStorageContainerId(groupId) - .build(); - } - - @Test - public void testGetActiveStreamRanges() throws Exception { - CompletableFuture serviceFuture = FutureUtils.createFuture(); - metaRangeClient.getStorageContainerClient().setStorageServerChannelFuture(serviceFuture); - - // create response - GetActiveRangesResponse getActiveRangesResponse = GetActiveRangesResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .addRanges( - buildRelatedRange(Long.MIN_VALUE, 0L, 123L, 1L, Lists.newArrayList(113L)) - ).addRanges( - buildRelatedRange(0L, Long.MAX_VALUE, 124L, 2L, Lists.newArrayList(114L)) - ).build(); - - MetaRangeServiceImplBase metaRangeService = new MetaRangeServiceImplBase() { - @Override - public void getActiveRanges(GetActiveRangesRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(getActiveRangesResponse); - responseObserver.onCompleted(); - } - }; - serviceRegistry.addService(metaRangeService.bindService()); - - @Cleanup StorageServerChannel rsChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serviceFuture.complete(rsChannel); - - HashStreamRanges expectedStream = createActiveRanges(getActiveRangesResponse); - CompletableFuture getFuture = metaRangeClient.getActiveDataRanges(); - assertEquals(expectedStream, getFuture.get()); - } - - @Test - public void testGetActiveStreamRangesFailure() throws Exception { - CompletableFuture serviceFuture = FutureUtils.createFuture(); - metaRangeClient.getStorageContainerClient().setStorageServerChannelFuture(serviceFuture); - - MetaRangeServiceImplBase metaRangeService = new MetaRangeServiceImplBase() { - @Override - public void getActiveRanges(GetActiveRangesRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - serviceRegistry.addService(metaRangeService.bindService()); - - @Cleanup StorageServerChannel rsChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serviceFuture.complete(rsChannel); - - CompletableFuture getFuture = metaRangeClient.getActiveDataRanges(); - try { - getFuture.get(); - fail("should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestProtocolInternalUtils.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestProtocolInternalUtils.java deleted file mode 100644 index 07bec6b581e..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestProtocolInternalUtils.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.clients.impl.internal.ProtocolInternalUtils.createActiveRanges; -import static org.apache.bookkeeper.clients.impl.internal.ProtocolInternalUtils.createMetaRangeException; -import static org.apache.bookkeeper.clients.impl.internal.ProtocolInternalUtils.createRootRangeException; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.INVALID_RANGE_ID; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetStorageContainerEndpointRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetStorageContainerEndpointResponse; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import java.util.List; -import java.util.TreeMap; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.InvalidNamespaceNameException; -import org.apache.bookkeeper.clients.exceptions.InvalidStreamNameException; -import org.apache.bookkeeper.clients.exceptions.NamespaceExistsException; -import org.apache.bookkeeper.clients.exceptions.NamespaceNotFoundException; -import org.apache.bookkeeper.clients.exceptions.StreamExistsException; -import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.HashStreamRanges; -import org.apache.bookkeeper.common.util.Revisioned; -import org.apache.bookkeeper.stream.proto.RangeKeyType; -import org.apache.bookkeeper.stream.proto.RangeProperties; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.RelatedRanges; -import org.apache.bookkeeper.stream.proto.storage.RelationType; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test for {@link ProtocolInternalUtils}. - */ -public class TestProtocolInternalUtils { - - @Rule - public final TestName name = new TestName(); - - // - // Test Meta KeyRange Server Requests - // - - @Test - public void testCreateActiveRanges() { - GetActiveRangesResponse.Builder responseBuilder = GetActiveRangesResponse.newBuilder(); - responseBuilder.addRanges( - RelatedRanges.newBuilder() - .setProps(RangeProperties.newBuilder() - .setStartHashKey(Long.MIN_VALUE) - .setEndHashKey(0L) - .setRangeId(1L) - .setStorageContainerId(1L)) - .setType(RelationType.PARENTS) - .addRelatedRanges(INVALID_RANGE_ID) - ).addRanges( - RelatedRanges.newBuilder() - .setProps(RangeProperties.newBuilder() - .setStartHashKey(0L) - .setEndHashKey(Long.MAX_VALUE) - .setRangeId(2L) - .setStorageContainerId(2L)) - .setType(RelationType.PARENTS) - .addRelatedRanges(INVALID_RANGE_ID)); - GetActiveRangesResponse response = responseBuilder.build(); - HashStreamRanges hsr = createActiveRanges(response); - TreeMap activeRanges = Maps.newTreeMap(); - activeRanges.put(Long.MIN_VALUE, response.getRanges(0).getProps()); - activeRanges.put(0L, response.getRanges(1).getProps()); - HashStreamRanges expectedHSR = HashStreamRanges.ofHash( - RangeKeyType.HASH, - activeRanges); - assertEquals(expectedHSR, hsr); - assertEquals(2L, hsr.getMaxRangeId()); - } - - @Test - public void testCreateActiveRangesInvalidKeyRange() { - GetActiveRangesResponse.Builder responseBuilder = GetActiveRangesResponse.newBuilder(); - responseBuilder.addRanges( - RelatedRanges.newBuilder() - .setProps(RangeProperties.newBuilder() - .setStartHashKey(Long.MIN_VALUE) - .setEndHashKey(0L) - .setRangeId(1L) - .setStorageContainerId(1L)) - .setType(RelationType.PARENTS) - .addRelatedRanges(INVALID_RANGE_ID) - ).addRanges( - RelatedRanges.newBuilder() - .setProps(RangeProperties.newBuilder() - .setStartHashKey(1L) - .setEndHashKey(Long.MAX_VALUE) - .setRangeId(2L) - .setStorageContainerId(2L)) - .setType(RelationType.PARENTS) - .addRelatedRanges(INVALID_RANGE_ID)); - try { - createActiveRanges(responseBuilder.build()); - fail("Should fail with invalid key range"); - } catch (IllegalStateException ise) { - assertEquals( - String.format("Invalid range key found : expected = %d, actual = %d", 0L, 1L), - ise.getMessage()); - } - } - - @Test - public void testCreateActiveRangesMissingKeyRange() { - GetActiveRangesResponse.Builder responseBuilder = GetActiveRangesResponse.newBuilder(); - responseBuilder.addRanges( - RelatedRanges.newBuilder() - .setProps(RangeProperties.newBuilder() - .setStartHashKey(Long.MIN_VALUE) - .setEndHashKey(0L) - .setRangeId(1L) - .setStorageContainerId(1L)) - .setType(RelationType.PARENTS) - .addRelatedRanges(INVALID_RANGE_ID) - ).addRanges( - RelatedRanges.newBuilder() - .setProps(RangeProperties.newBuilder() - .setStartHashKey(0L) - .setEndHashKey(1234L) - .setRangeId(2L) - .setStorageContainerId(2L)) - .setType(RelationType.PARENTS) - .addRelatedRanges(INVALID_RANGE_ID)); - try { - createActiveRanges(responseBuilder.build()); - fail("Should fail with missing key range"); - } catch (IllegalStateException ise) { - assertEquals( - String.format("Missing key range [%d - %d)", 1234L, Long.MAX_VALUE), - ise.getMessage()); - } - } - - // - // Test Location Server Requests - // - - @Test - public void testCreateGetStorageContainerEndpointRequest() { - List> scs = Lists.newArrayList( - Revisioned.of(1000L, 1L), - Revisioned.of(2000L, 2L), - Revisioned.of(3000L, 3L)); - GetStorageContainerEndpointRequest request = createGetStorageContainerEndpointRequest(scs); - assertEquals(3, request.getRequestsCount()); - int i = 1; - for (OneStorageContainerEndpointRequest oneRequest : request.getRequestsList()) { - assertEquals(1000L * i, oneRequest.getStorageContainer()); - assertEquals(1L * i, oneRequest.getRevision()); - ++i; - } - } - - @Test - public void testCreateStorageContainerEndpointResponse() { - List endpoints = Lists.newArrayList( - StorageContainerEndpoint.newBuilder().setStorageContainerId(1L).build(), - StorageContainerEndpoint.newBuilder().setStorageContainerId(2L).build(), - StorageContainerEndpoint.newBuilder().setStorageContainerId(3L).build()); - GetStorageContainerEndpointResponse response = createGetStorageContainerEndpointResponse(endpoints); - assertEquals(3, response.getResponsesCount()); - int i = 0; - for (OneStorageContainerEndpointResponse oneResp : response.getResponsesList()) { - assertEquals(StatusCode.SUCCESS, oneResp.getStatusCode()); - assertTrue(endpoints.get(i) == oneResp.getEndpoint()); - ++i; - } - } - - // - // Test Exceptions related utils - // - - @Test - public void testCreateRootRangeException() { - String name = "test-create-root-range-exception"; - // stream exists exception - Throwable cause1 = createRootRangeException(name, StatusCode.STREAM_EXISTS); - assertTrue(cause1 instanceof StreamExistsException); - StreamExistsException see = (StreamExistsException) cause1; - // stream not found - Throwable cause2 = createRootRangeException(name, StatusCode.STREAM_NOT_FOUND); - assertTrue(cause2 instanceof StreamNotFoundException); - StreamNotFoundException snfe = (StreamNotFoundException) cause2; - // invalid stream name - Throwable invalidStreamNameCause = createRootRangeException(name, StatusCode.INVALID_STREAM_NAME); - assertTrue(invalidStreamNameCause instanceof InvalidStreamNameException); - InvalidStreamNameException isne = (InvalidStreamNameException) invalidStreamNameCause; - // failure - Throwable cause3 = createRootRangeException(name, StatusCode.FAILURE); - ClientException se = (ClientException) cause3; - assertEquals("fail to access its root range : code = " + StatusCode.FAILURE, - se.getMessage()); - // namespace exists exception - Throwable cause5 = createRootRangeException(name, StatusCode.NAMESPACE_EXISTS); - assertTrue(cause5 instanceof NamespaceExistsException); - // namespace not-found exception - Throwable cause6 = createRootRangeException(name, StatusCode.NAMESPACE_NOT_FOUND); - assertTrue(cause6 instanceof NamespaceNotFoundException); - // invalid namespace name - Throwable cause7 = createRootRangeException(name, StatusCode.INVALID_NAMESPACE_NAME); - assertTrue(cause7 instanceof InvalidNamespaceNameException); - } - - @Test - public void testMetaRangeException() { - String name = "test-meta-range-exception"; - - // stream exists - Throwable existCause = createMetaRangeException(name, StatusCode.STREAM_EXISTS); - assertTrue(existCause instanceof StreamExistsException); - - // stream not found - Throwable notFoundCause = createMetaRangeException(name, StatusCode.STREAM_NOT_FOUND); - assertTrue(notFoundCause instanceof StreamNotFoundException); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java deleted file mode 100644 index 111ac665119..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.NamespaceNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; - -/** - * Test Case for {@link RootRangeClientImpl}: CreateNamespace. - */ -public class TestRootRangeClientCreateNamespaceRpc extends RootRangeClientImplTestBase { - - private long colId; - private String colName; - private NamespaceProperties colProps; - private static final NamespaceConfiguration colConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - - @Override - protected void doSetup() throws Exception { - super.doSetup(); - - this.colId = System.currentTimeMillis(); - this.colName = testName.getMethodName(); - this.colProps = NamespaceProperties.newBuilder() - .setNamespaceId(colId) - .setNamespaceName(colName) - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - } - - // - // Test StorageClient Operations - // - - // - // Namespace API - // - - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForSuccess() { - return new RootRangeServiceImplBase() { - @Override - public void createNamespace(CreateNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(CreateNamespaceResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setNsProps(colProps) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifySuccess(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture createFuture = rootRangeClient.createNamespace(colName, colConf); - assertTrue(colProps == createFuture.get()); - } - - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRequestFailure() { - return new RootRangeServiceImplBase() { - @Override - public void createNamespace(CreateNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(CreateNamespaceResponse.newBuilder() - .setCode(StatusCode.NAMESPACE_NOT_FOUND) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture createFuture = rootRangeClient.createNamespace(colName, colConf); - try { - createFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof NamespaceNotFoundException); - } - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRpcFailure() { - return new RootRangeServiceImplBase() { - @Override - public void createNamespace(CreateNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - } - - @Override - protected void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture createFuture = rootRangeClient.createNamespace(colName, colConf); - try { - createFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - - @Override - protected void verifyChannelFailure(IOException expectedException, RootRangeClient rootRangeClient) - throws Exception { - CompletableFuture createFuture = rootRangeClient.createNamespace(colName, colConf); - try { - createFuture.get(); - fail("Should fail on creating stream"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ClientException); - ClientException zse = (ClientException) ee.getCause(); - assertNotNull(zse.getCause()); - assertTrue(expectedException == zse.getCause()); - } - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateStreamRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateStreamRpc.java deleted file mode 100644 index 62c395af10b..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateStreamRpc.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; - -/** - * Test Case for {@link RootRangeClientImpl}: CreateStream. - */ -public class TestRootRangeClientCreateStreamRpc extends RootRangeClientImplTestBase { - - private long streamId; - private String colName; - private String streamName; - private StreamProperties streamProps; - private static final StreamConfiguration streamConf = DEFAULT_STREAM_CONF; - - @Override - protected void doSetup() throws Exception { - super.doSetup(); - - this.streamId = System.currentTimeMillis(); - this.colName = testName.getMethodName() + "_col"; - this.streamName = testName.getMethodName() + "_stream"; - this.streamProps = StreamProperties.newBuilder() - .setStorageContainerId(System.currentTimeMillis()) - .setStreamId(streamId) - .setStreamName(streamName) - .setStreamConf(DEFAULT_STREAM_CONF) - .build(); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForSuccess() { - return new RootRangeServiceImplBase() { - @Override - public void createStream(CreateStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(CreateStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setStreamProps(streamProps) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifySuccess(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture createFuture = - rootRangeClient.createStream(colName, streamName, streamConf); - assertTrue(streamProps == createFuture.get()); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRequestFailure() { - return new RootRangeServiceImplBase() { - @Override - public void createStream(CreateStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(CreateStreamResponse.newBuilder() - .setCode(StatusCode.STREAM_NOT_FOUND) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture createFuture = - rootRangeClient.createStream(colName, streamName, streamConf); - try { - createFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StreamNotFoundException); - } - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRpcFailure() { - return new RootRangeServiceImplBase() { - @Override - public void createStream(CreateStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - } - - @Override - protected void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture createFuture = - rootRangeClient.createStream(colName, streamName, streamConf); - try { - createFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - - @Override - protected void verifyChannelFailure(IOException expectedException, - RootRangeClient rootRangeClient) throws Exception { - - CompletableFuture createFuture = - rootRangeClient.createStream(colName, streamName, streamConf); - try { - createFuture.get(); - fail("Should fail on creating stream"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ClientException); - ClientException zse = (ClientException) ee.getCause(); - assertNotNull(zse.getCause()); - assertTrue(expectedException == zse.getCause()); - } - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteNamespaceRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteNamespaceRpc.java deleted file mode 100644 index f8ce93068d6..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteNamespaceRpc.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.NamespaceNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; - -/** - * Test Case for {@link RootRangeClientImpl}: DeleteNamespace. - */ -public class TestRootRangeClientDeleteNamespaceRpc extends RootRangeClientImplTestBase { - - private String colName; - - @Override - protected void doSetup() throws Exception { - super.doSetup(); - - this.colName = testName.getMethodName(); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForSuccess() { - return new RootRangeServiceImplBase() { - @Override - public void deleteNamespace(DeleteNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(DeleteNamespaceResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifySuccess(RootRangeClient rootRangeClient) throws Exception { - rootRangeClient.deleteNamespace(colName).get(); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRequestFailure() { - return new RootRangeServiceImplBase() { - @Override - public void deleteNamespace(DeleteNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(DeleteNamespaceResponse.newBuilder() - .setCode(StatusCode.NAMESPACE_NOT_FOUND) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture deleteFuture = rootRangeClient.deleteNamespace(colName); - try { - deleteFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof NamespaceNotFoundException); - } - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRpcFailure() { - return new RootRangeServiceImplBase() { - @Override - public void deleteNamespace(DeleteNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - } - - @Override - protected void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture deleteFuture = rootRangeClient.deleteNamespace(colName); - try { - deleteFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - - @Override - protected void verifyChannelFailure(IOException expectedException, - RootRangeClient rootRangeClient) throws Exception { - CompletableFuture deleteFuture = rootRangeClient.deleteNamespace(colName); - try { - deleteFuture.get(); - fail("Should fail on rpc operation"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ClientException); - ClientException zse = (ClientException) ee.getCause(); - assertNotNull(zse.getCause()); - assertTrue(expectedException == zse.getCause()); - } - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteStreamRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteStreamRpc.java deleted file mode 100644 index bd8f5494fa2..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientDeleteStreamRpc.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; - -/** - * Test Case for {@link RootRangeClientImpl}: DeleteNamespace. - */ -public class TestRootRangeClientDeleteStreamRpc extends RootRangeClientImplTestBase { - - private String colName; - private String streamName; - - @Override - protected void doSetup() throws Exception { - super.doSetup(); - - this.colName = testName.getMethodName() + "_col"; - this.streamName = testName.getMethodName() + "_col"; - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForSuccess() { - return new RootRangeServiceImplBase() { - @Override - public void deleteStream(DeleteStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(DeleteStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifySuccess(RootRangeClient rootRangeClient) throws Exception { - assertTrue(rootRangeClient.deleteStream(colName, streamName).get()); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRequestFailure() { - return new RootRangeServiceImplBase() { - @Override - public void deleteStream(DeleteStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(DeleteStreamResponse.newBuilder() - .setCode(StatusCode.STREAM_NOT_FOUND) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture deleteFuture = rootRangeClient.deleteStream(colName, streamName); - try { - deleteFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StreamNotFoundException); - } - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRpcFailure() { - return new RootRangeServiceImplBase() { - @Override - public void deleteStream(DeleteStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - } - - @Override - protected void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture deleteFuture = rootRangeClient.deleteStream(colName, streamName); - try { - deleteFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - - @Override - protected void verifyChannelFailure(IOException expectedException, - RootRangeClient rootRangeClient) throws Exception { - CompletableFuture deleteFuture = rootRangeClient.deleteStream(colName, streamName); - try { - deleteFuture.get(); - fail("Should fail on rpc operation"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ClientException); - ClientException zse = (ClientException) ee.getCause(); - assertNotNull(zse.getCause()); - assertTrue(expectedException == zse.getCause()); - } - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java deleted file mode 100644 index edbfeecb86a..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.NamespaceNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; - -/** - * Test Case for {@link RootRangeClientImpl}: CreateNamespace. - */ -public class TestRootRangeClientGetNamespaceRpc extends RootRangeClientImplTestBase { - - private long colId; - private String colName; - private NamespaceProperties colProps; - private static final NamespaceConfiguration colConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - - @Override - protected void doSetup() throws Exception { - super.doSetup(); - - this.colId = System.currentTimeMillis(); - this.colName = testName.getMethodName(); - this.colProps = NamespaceProperties.newBuilder() - .setNamespaceId(colId) - .setNamespaceName(colName) - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - } - - // - // Test Client Operations - // - - // - // Namespace API - // - - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForSuccess() { - return new RootRangeServiceImplBase() { - @Override - public void getNamespace(GetNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetNamespaceResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setNsProps(colProps) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifySuccess(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getNamespace(colName); - assertTrue(colProps == getFuture.get()); - } - - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRequestFailure() { - return new RootRangeServiceImplBase() { - @Override - public void getNamespace(GetNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetNamespaceResponse.newBuilder() - .setCode(StatusCode.NAMESPACE_NOT_FOUND) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getNamespace(colName); - try { - getFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof NamespaceNotFoundException); - } - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRpcFailure() { - return new RootRangeServiceImplBase() { - @Override - public void getNamespace(GetNamespaceRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - } - - @Override - protected void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getNamespace(colName); - try { - getFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - - @Override - protected void verifyChannelFailure(IOException expectedException, - RootRangeClient rootRangeClient) throws Exception { - CompletableFuture createFuture = rootRangeClient.createNamespace(colName, colConf); - try { - createFuture.get(); - fail("Should fail on creating stream"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ClientException); - ClientException zse = (ClientException) ee.getCause(); - assertNotNull(zse.getCause()); - assertTrue(expectedException == zse.getCause()); - } - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamByIdRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamByIdRpc.java deleted file mode 100644 index 388dab12cdb..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamByIdRpc.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; - -/** - * Test Case for {@link RootRangeClientImpl}: CreateStream. - */ -public class TestRootRangeClientGetStreamByIdRpc extends RootRangeClientImplTestBase { - - private long streamId; - private StreamProperties streamProps; - - @Override - protected void doSetup() throws Exception { - super.doSetup(); - - this.streamId = System.currentTimeMillis(); - String streamName = testName.getMethodName() + "_stream"; - this.streamProps = StreamProperties.newBuilder() - .setStorageContainerId(System.currentTimeMillis()) - .setStreamId(streamId) - .setStreamName(streamName) - .setStreamConf(DEFAULT_STREAM_CONF) - .build(); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForSuccess() { - return new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setStreamProps(streamProps) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifySuccess(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getStream(streamId); - assertTrue(streamProps == getFuture.get()); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRequestFailure() { - return new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetStreamResponse.newBuilder() - .setCode(StatusCode.STREAM_NOT_FOUND) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getStream(streamId); - try { - getFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StreamNotFoundException); - } - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRpcFailure() { - return new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - } - - @Override - protected void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getStream(streamId); - try { - getFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - - @Override - protected void verifyChannelFailure(IOException expectedException, - RootRangeClient rootRangeClient) throws Exception { - - CompletableFuture getFuture = rootRangeClient.getStream(streamId); - try { - getFuture.get(); - fail("Should fail on creating stream"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ClientException); - ClientException zse = (ClientException) ee.getCause(); - assertNotNull(zse.getCause()); - assertTrue(expectedException == zse.getCause()); - } - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamRpc.java deleted file mode 100644 index d9d66681a60..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetStreamRpc.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException; -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; - -/** - * Test Case for {@link RootRangeClientImpl}: CreateStream. - */ -public class TestRootRangeClientGetStreamRpc extends RootRangeClientImplTestBase { - - private long streamId; - private String colName; - private String streamName; - private StreamProperties streamProps; - - @Override - protected void doSetup() throws Exception { - super.doSetup(); - - this.streamId = System.currentTimeMillis(); - this.colName = testName.getMethodName() + "_col"; - this.streamName = testName.getMethodName() + "_stream"; - this.streamProps = StreamProperties.newBuilder() - .setStorageContainerId(System.currentTimeMillis()) - .setStreamId(streamId) - .setStreamName(streamName) - .setStreamConf(DEFAULT_STREAM_CONF) - .build(); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForSuccess() { - return new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setStreamProps(streamProps) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifySuccess(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getStream(colName, streamName); - assertTrue(streamProps == getFuture.get()); - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRequestFailure() { - return new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetStreamResponse.newBuilder() - .setCode(StatusCode.STREAM_NOT_FOUND) - .build()); - responseObserver.onCompleted(); - } - }; - } - - @Override - protected void verifyRequestFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getStream(colName, streamName); - try { - getFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StreamNotFoundException); - } - } - - @Override - protected RootRangeServiceImplBase createRootRangeServiceForRpcFailure() { - return new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onError(new StatusRuntimeException(Status.INTERNAL)); - } - }; - } - - @Override - protected void verifyRpcFailure(RootRangeClient rootRangeClient) throws Exception { - CompletableFuture getFuture = rootRangeClient.getStream(colName, streamName); - try { - getFuture.get(); - fail("Should fail on rpc failure"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException se = (StatusRuntimeException) ee.getCause(); - assertEquals(Status.INTERNAL, se.getStatus()); - } - } - - @Override - protected void verifyChannelFailure(IOException expectedException, - RootRangeClient rootRangeClient) throws Exception { - - CompletableFuture getFuture = rootRangeClient.getStream(colName, streamName); - try { - getFuture.get(); - fail("Should fail on creating stream"); - } catch (ExecutionException ee) { - assertNotNull(ee.getCause()); - assertTrue(ee.getCause() instanceof ClientException); - ClientException zse = (ClientException) ee.getCause(); - assertNotNull(zse.getCause()); - assertTrue(expectedException == zse.getCause()); - } - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStorageServerClientManagerImpl.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStorageServerClientManagerImpl.java deleted file mode 100644 index d72a69e431e..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStorageServerClientManagerImpl.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import io.grpc.stub.StreamObserver; -import java.util.List; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.internal.api.LocationClient; -import org.apache.bookkeeper.clients.impl.internal.api.MetaRangeClient; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.Revisioned; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Test Case for {@link StorageServerClientManagerImpl}. - */ -public class TestStorageServerClientManagerImpl extends GrpcClientTestBase { - - @Override - protected void doSetup() throws Exception { - } - - @Override - protected void doTeardown() throws Exception { - } - - @Test - public void testGetMetaRangeClient() throws Exception { - long streamId = 3456L; - StreamProperties props = StreamProperties.newBuilder() - .setStorageContainerId(1234L) - .setStreamId(streamId) - .setStreamName("metaclient-stream") - .setStreamConf(StreamConfiguration.newBuilder().build()) - .build(); - - MetaRangeClientImpl metaRangeClient = serverManager.openMetaRangeClient(props); - assertEquals(1234L, metaRangeClient.getStorageContainerClient().getStorageContainerId()); - assertTrue(props == metaRangeClient.getStreamProps()); - - // the stream properties will be cached here - assertEquals(props, FutureUtils.result(serverManager.getStreamProperties(streamId))); - - // the metadata range client is cached as well - assertEquals(metaRangeClient, FutureUtils.result(serverManager.openMetaRangeClient(streamId))); - } - - @Test - public void testGetMetaRangeClientByStreamId() throws Exception { - long streamId = 3456L; - StreamProperties props = StreamProperties.newBuilder() - .setStorageContainerId(1234L) - .setStreamId(streamId) - .setStreamName("metaclient-stream") - .setStreamConf(StreamConfiguration.newBuilder().build()) - .build(); - - RootRangeServiceImplBase rootRangeService = new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setStreamProps(props) - .build()); - responseObserver.onCompleted(); - } - }; - serviceRegistry.addService(rootRangeService.bindService()); - - // the stream properties will be cached here - assertEquals(props, FutureUtils.result(serverManager.getStreamProperties(streamId))); - - // the metadata range client is cached as well - MetaRangeClient client = FutureUtils.result(serverManager.openMetaRangeClient(streamId)); - assertEquals(props, client.getStreamProps()); - } - - @SuppressWarnings("unchecked") - @Test - public void testGetLocationClient() throws Exception { - LocationClient lc = serverManager.getLocationClient(); - assertNotNull(lc); - assertEquals(lc, serverManager.getLocationClient()); - List responses = - FutureUtils.result(lc.locateStorageContainers(Lists.newArrayList(Revisioned.of(123L, 456L)))); - assertEquals(1, responses.size()); - assertEquals(StatusCode.SUCCESS, responses.get(0).getStatusCode()); - assertEquals(ENDPOINT, responses.get(0).getEndpoint().getRwEndpoint()); - assertEquals(0, responses.get(0).getEndpoint().getRoEndpointCount()); - } - - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStreamMetadataCache.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStreamMetadataCache.java deleted file mode 100644 index 54b902d5885..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestStreamMetadataCache.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.clients.impl.internal.api.RootRangeClient; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.junit.Test; - -/** - * Unit test of {@link StreamMetadataCache}. - */ -public class TestStreamMetadataCache { - - private final RootRangeClient scClient = mock(RootRangeClient.class); - private final StreamMetadataCache cache = new StreamMetadataCache(scClient); - private final StreamProperties props = StreamProperties.newBuilder() - .setStorageContainerId(1234L) - .setStreamId(2345L) - .setStreamName("test-stream") - .setStreamConf(DEFAULT_STREAM_CONF) - .build(); - - @Test - public void testGetStreamProperties() throws Exception { - when(scClient.getStream(anyLong())) - .thenReturn(FutureUtils.value(props)); - assertEquals(0, cache.getStreams().size()); - assertEquals(props, FutureUtils.result(cache.getStreamProperties(1234L))); - assertEquals(1, cache.getStreams().size()); - verify(scClient, times(1)).getStream(eq(1234L)); - } - - @Test - public void testPutStreamProperties() throws Exception { - assertEquals(0, cache.getStreams().size()); - assertTrue(cache.putStreamProperties(1234L, props)); - assertEquals(1, cache.getStreams().size()); - assertFalse(cache.putStreamProperties(1234L, props)); - assertEquals(1, cache.getStreams().size()); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestHashStreamRanges.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestHashStreamRanges.java deleted file mode 100644 index 5e215a55a09..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestHashStreamRanges.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal.api; - -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Maps; -import java.util.NavigableMap; -import org.apache.bookkeeper.stream.proto.RangeKeyType; -import org.apache.bookkeeper.stream.proto.RangeProperties; -import org.junit.Test; - -/** - * Unit test for {@link HashStreamRanges}. - */ -public class TestHashStreamRanges { - - @Test - public void testConstructor() { - NavigableMap ranges = Maps.newTreeMap(); - for (long hashKey = 0L; hashKey < 10L; hashKey++) { - RangeProperties props = RangeProperties.newBuilder() - .setStorageContainerId(hashKey) - .setRangeId(hashKey) - .setStartHashKey(hashKey) - .setEndHashKey(hashKey) - .build(); - ranges.put(hashKey, props); - } - - HashStreamRanges hsr = new HashStreamRanges( - ranges, - 9L); - - assertEquals(RangeKeyType.HASH, hsr.getKeyType()); - assertEquals(ranges, hsr.getRanges()); - assertEquals(9L, hsr.getMaxRangeId()); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestStreamRanges.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestStreamRanges.java deleted file mode 100644 index 59a74c6dfa3..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/api/TestStreamRanges.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.impl.internal.api; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import com.google.common.collect.Maps; -import java.util.NavigableMap; -import org.apache.bookkeeper.stream.proto.RangeKeyType; -import org.apache.bookkeeper.stream.proto.RangeProperties; -import org.junit.Test; - -/** - * Unit test for {@link StreamRanges}. - */ -public class TestStreamRanges { - - @Test(expected = IllegalArgumentException.class) - public void testInvalidRangeKeyType() { - StreamRanges.ofHash(RangeKeyType.RAW, Maps.newTreeMap()); - } - - @Test - public void testConstructor() { - NavigableMap ranges = Maps.newTreeMap(); - for (long hashKey = 0L; hashKey < 10L; hashKey++) { - RangeProperties props = RangeProperties.newBuilder() - .setStorageContainerId(hashKey) - .setRangeId(hashKey) - .setStartHashKey(hashKey) - .setEndHashKey(hashKey) - .build(); - ranges.put(hashKey, props); - } - - HashStreamRanges hsr = StreamRanges.ofHash( - RangeKeyType.HASH, - ranges); - - assertEquals(RangeKeyType.HASH, hsr.getKeyType()); - assertEquals(ranges, hsr.getRanges()); - assertEquals(9L, hsr.getMaxRangeId()); - } - - @Test - public void testEqual() { - NavigableMap ranges1 = Maps.newTreeMap(); - NavigableMap ranges2 = Maps.newTreeMap(); - for (long hashKey = 0L; hashKey < 10L; hashKey++) { - RangeProperties props1 = RangeProperties.newBuilder() - .setStorageContainerId(hashKey) - .setRangeId(hashKey) - .setStartHashKey(hashKey) - .setEndHashKey(hashKey) - .build(); - ranges1.put(hashKey, props1); - RangeProperties props2 = RangeProperties.newBuilder() - .setStorageContainerId(hashKey) - .setRangeId(hashKey) - .setStartHashKey(hashKey) - .setEndHashKey(hashKey) - .build(); - ranges2.put(hashKey, props2); - } - - HashStreamRanges hsr1 = StreamRanges.ofHash( - RangeKeyType.HASH, - ranges1); - HashStreamRanges hsr2 = StreamRanges.ofHash( - RangeKeyType.HASH, - ranges2); - - assertEquals(hsr1, hsr2); - } - - @Test - public void testNotEqual() { - NavigableMap ranges1 = Maps.newTreeMap(); - NavigableMap ranges2 = Maps.newTreeMap(); - for (long hashKey = 0L; hashKey < 10L; hashKey++) { - RangeProperties props1 = RangeProperties.newBuilder() - .setStorageContainerId(hashKey) - .setRangeId(hashKey) - .setStartHashKey(hashKey) - .setEndHashKey(hashKey) - .build(); - ranges1.put(hashKey, props1); - RangeProperties props2 = RangeProperties.newBuilder() - .setStorageContainerId(hashKey) - .setRangeId(hashKey + 1) - .setStartHashKey(hashKey + 1) - .setEndHashKey(hashKey + 1) - .build(); - ranges2.put(hashKey, props2); - } - - HashStreamRanges hsr1 = StreamRanges.ofHash( - RangeKeyType.HASH, - ranges1); - HashStreamRanges hsr2 = StreamRanges.ofHash( - RangeKeyType.HASH, - ranges2); - - assertNotEquals(hsr1, hsr2); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/GrpcChannelsTest.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/GrpcChannelsTest.java deleted file mode 100644 index 3e3e81e98e8..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/GrpcChannelsTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.utils; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.grpc.ManagedChannelBuilder; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.netty.NettyChannelBuilder; -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.junit.Test; - -/** - * Unit test {@link GrpcChannels}. - */ -public class GrpcChannelsTest { - - @Test - public void testInprocessServiceUri() { - String serviceUri = "bk+inprocess://service"; - ManagedChannelBuilder builder = GrpcChannels.createChannelBuilder( - serviceUri, - StorageClientSettings.newBuilder().serviceUri(serviceUri).build() - ); - assertTrue(builder instanceof InProcessChannelBuilder); - } - - @Test - public void testBKServiceUri() { - String serviceUri = "bk://127.0.0.1"; - ManagedChannelBuilder builder = GrpcChannels.createChannelBuilder( - serviceUri, - StorageClientSettings.newBuilder().serviceUri(serviceUri).build() - ); - assertTrue(builder instanceof NettyChannelBuilder); - } - - @Test - public void testZKServiceUri() { - String serviceUri = "zk://127.0.0.1/stream/servers"; - try { - GrpcChannels.createChannelBuilder( - serviceUri, - StorageClientSettings.newBuilder().serviceUri(serviceUri).build() - ); - fail("Should fail to create grpc channel because `bk-grpc-name-resolver` is not in the classpath"); - } catch (RuntimeException re) { - assertTrue(re.getCause() instanceof ClassNotFoundException); - } - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/ListenableFutureRpcProcessorTest.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/ListenableFutureRpcProcessorTest.java deleted file mode 100644 index 2c229cbc838..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/ListenableFutureRpcProcessorTest.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.utils; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link ListenableFutureRpcProcessor}. - */ -public class ListenableFutureRpcProcessorTest { - - private ListenableFutureRpcProcessor processor; - private StorageContainerChannel scChannel; - private ScheduledExecutorService executor; - - @Before - public void setup() { - executor = Executors.newSingleThreadScheduledExecutor(); - scChannel = mock(StorageContainerChannel.class); - processor = spy(new ListenableFutureRpcProcessor( - scChannel, executor, ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY) { - @Override - protected String createRequest() { - return null; - } - - @Override - protected ListenableFuture sendRPC(StorageServerChannel rsChannel, String s) { - return null; - } - - @Override - protected String processResponse(String response) throws Exception { - return null; - } - }); - } - - @Test - public void testFailToConnect() { - CompletableFuture serverFuture = new CompletableFuture<>(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverFuture); - - CompletableFuture resultFuture = processor.process(); - verify(scChannel, times(1)).getStorageContainerChannelFuture(); - - // inject channel failure - Exception testExc = new Exception("test-exception"); - serverFuture.completeExceptionally(testExc); - - try { - FutureUtils.result(resultFuture); - fail("Should fail the process if failed to connect to storage server"); - } catch (Exception e) { - assertSame(testExc, e); - } - } - - @Test - public void testProcessSuccessfully() throws Exception { - String request = "request"; - String response = "response"; - String result = "result"; - - StorageServerChannel serverChannel = mock(StorageServerChannel.class); - - CompletableFuture serverFuture = new CompletableFuture<>(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverFuture); - - SettableFuture rpcFuture = SettableFuture.create(); - - // mock the process method - when(processor.createRequest()).thenReturn(request); - when(processor.sendRPC(same(serverChannel), eq(request))).thenReturn(rpcFuture); - when(processor.processResponse(eq(response))).thenReturn(result); - - CompletableFuture resultFuture = processor.process(); - verify(scChannel, times(1)).getStorageContainerChannelFuture(); - - // complete the server future to return a mock server channel - FutureUtils.complete(serverFuture, serverChannel); - - // complete the rpc future to return the response - rpcFuture.set(response); - - assertEquals(result, resultFuture.get()); - } - - @Test - public void testProcessResponseException() throws Exception { - String request = "request"; - String response = "response"; - - StorageServerChannel serverChannel = mock(StorageServerChannel.class); - - CompletableFuture serverFuture = new CompletableFuture<>(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverFuture); - - SettableFuture rpcFuture = SettableFuture.create(); - - Exception testException = new Exception("test-exception"); - - // mock the process method - when(processor.createRequest()).thenReturn(request); - when(processor.sendRPC(same(serverChannel), eq(request))).thenReturn(rpcFuture); - when(processor.processResponse(eq(response))).thenThrow(testException); - - CompletableFuture resultFuture = processor.process(); - verify(scChannel, times(1)).getStorageContainerChannelFuture(); - - // complete the server future to return a mock server channel - FutureUtils.complete(serverFuture, serverChannel); - - // complete the rpc future to return the response - rpcFuture.set(response); - - try { - FutureUtils.result(resultFuture); - fail("Should throw exception on processing result"); - } catch (Exception e) { - assertSame(testException, e); - } - } - - @Test - public void testProcessRpcException() throws Exception { - String request = "request"; - String response = "response"; - String result = "result"; - - StorageServerChannel serverChannel = mock(StorageServerChannel.class); - - CompletableFuture serverFuture = new CompletableFuture<>(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverFuture); - - SettableFuture rpcFuture = SettableFuture.create(); - - // mock the process method - when(processor.createRequest()).thenReturn(request); - when(processor.sendRPC(same(serverChannel), eq(request))).thenReturn(rpcFuture); - when(processor.processResponse(eq(response))).thenReturn(result); - - CompletableFuture resultFuture = processor.process(); - verify(scChannel, times(1)).getStorageContainerChannelFuture(); - - // complete the server future to return a mock server channel - FutureUtils.complete(serverFuture, serverChannel); - - // complete the rpc future with `Status.INTERNAL` - rpcFuture.setException(new StatusRuntimeException(Status.INTERNAL)); - - try { - FutureUtils.result(resultFuture); - fail("Should throw fail immediately if rpc request failed"); - } catch (Exception e) { - assertTrue(e instanceof StatusRuntimeException); - StatusRuntimeException sre = (StatusRuntimeException) e; - assertEquals(Status.INTERNAL, sre.getStatus()); - } - } - - @Test - public void testProcessRetryNotFoundRpcException() throws Exception { - String request = "request"; - String response = "response"; - String result = "result"; - - StorageServerChannel serverChannel = mock(StorageServerChannel.class); - - CompletableFuture serverFuture = new CompletableFuture<>(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverFuture); - - AtomicInteger numRpcs = new AtomicInteger(0); - - // mock the process method - when(processor.createRequest()).thenReturn(request); - when(processor.processResponse(eq(response))).thenReturn(result); - when(processor.sendRPC(same(serverChannel), eq(request))).thenAnswer(invocationOnMock -> { - SettableFuture rpcFuture = SettableFuture.create(); - if (numRpcs.getAndIncrement() > 2) { - rpcFuture.set(response); - } else { - rpcFuture.setException(new StatusRuntimeException(Status.NOT_FOUND)); - } - return rpcFuture; - }); - - CompletableFuture resultFuture = processor.process(); - - // complete the server future to return a mock server channel - FutureUtils.complete(serverFuture, serverChannel); - - assertEquals(result, FutureUtils.result(resultFuture)); - verify(scChannel, times(4)).getStorageContainerChannelFuture(); - } -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/RpcUtilsTest.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/RpcUtilsTest.java deleted file mode 100644 index d97d4e43236..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/RpcUtilsTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.utils; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import io.grpc.Status; -import io.grpc.StatusException; -import io.grpc.StatusRuntimeException; -import org.junit.Test; - -/** - * Unit test {@link RpcUtils}. - */ -public class RpcUtilsTest { - - @Test - public void testIsContainerNotFound() { - StatusRuntimeException trueSRE = new StatusRuntimeException(Status.NOT_FOUND); - assertTrue(RpcUtils.isContainerNotFound(trueSRE)); - StatusRuntimeException falseSRE = new StatusRuntimeException(Status.INTERNAL); - assertFalse(RpcUtils.isContainerNotFound(falseSRE)); - - StatusException trueSE = new StatusException(Status.NOT_FOUND); - assertTrue(RpcUtils.isContainerNotFound(trueSE)); - StatusException falseSE = new StatusException(Status.INTERNAL); - assertFalse(RpcUtils.isContainerNotFound(falseSE)); - - Exception unknownException = new Exception("unknown"); - assertFalse(RpcUtils.isContainerNotFound(unknownException)); - } - -} diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/TestNetUtils.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/TestNetUtils.java deleted file mode 100644 index 9f98b8d9c59..00000000000 --- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/utils/TestNetUtils.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.clients.utils; - -import static org.apache.bookkeeper.clients.utils.NetUtils.createEndpoint; -import static org.apache.bookkeeper.clients.utils.NetUtils.parseEndpoint; -import static org.apache.bookkeeper.clients.utils.NetUtils.parseEndpoints; -import static org.junit.Assert.assertEquals; - -import com.google.common.collect.Lists; -import java.net.InetSocketAddress; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.commons.lang.StringUtils; -import org.junit.Test; - -/** - * Unit test for {@link NetUtils}. - */ -public class TestNetUtils { - - @Test - public void testCreateEndpoint() { - String hostname = "10.138.10.56"; - int port = 12345; - Endpoint endpoint = createEndpoint(hostname, port); - assertEquals(hostname, endpoint.getHostname()); - assertEquals(port, endpoint.getPort()); - } - - @Test - public void testParseEndpoint() { - String endpointStr = "10.138.10.56:12345"; - Endpoint endpoint = parseEndpoint(endpointStr); - assertEquals("10.138.10.56", endpoint.getHostname()); - assertEquals(12345, endpoint.getPort()); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseInvalidEndpoint1() { - parseEndpoint("10.138.10.56"); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseInvalidEndpoint2() { - parseEndpoint("10.138.10.56:"); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseInvalidEndpoint3() { - parseEndpoint("10.138.10.56:123456:123456"); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseInvalidEndpointPort() { - parseEndpoint("10.138.10.56:abcd"); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseEmptyEndpoints() { - parseEndpoint(""); - } - - @Test - public void testParseEndpoints() { - List hostnames = Lists.newArrayList( - "10.138.10.56", - "10.138.10.57", - "10.138.10.58"); - List ports = Lists.newArrayList( - 1234, - 2345, - 3456); - List endpoints = IntStream.range(0, hostnames.size()) - .mapToObj(i -> createEndpoint(hostnames.get(i), ports.get(i))) - .collect(Collectors.toList()); - String endpointStr = - StringUtils.join( - IntStream.range(0, hostnames.size()) - .mapToObj(i -> hostnames.get(i) + ":" + ports.get(i)) - .collect(Collectors.toList()), - ','); - List parsedEndpoints = parseEndpoints(endpointStr); - assertEquals(endpoints, parsedEndpoints); - } - - @Test - public void testToInetSocketAddress() { - String hostname = "127.0.0.1"; - int port = 8080; - Endpoint endpoint = createEndpoint(hostname, port); - InetSocketAddress socketAddress = new InetSocketAddress(hostname, port); - assertEquals(socketAddress, NetUtils.of(endpoint)); - } - -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/ByteBufTableImplTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/ByteBufTableImplTest.java deleted file mode 100644 index 1b2f7676173..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/ByteBufTableImplTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.impl.kv; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.apache.bookkeeper.api.kv.PTable; -import org.apache.bookkeeper.api.kv.impl.options.OptionFactoryImpl; -import org.apache.bookkeeper.api.kv.options.DeleteOption; -import org.apache.bookkeeper.api.kv.options.IncrementOption; -import org.apache.bookkeeper.api.kv.options.OptionFactory; -import org.apache.bookkeeper.api.kv.options.PutOption; -import org.apache.bookkeeper.api.kv.options.RangeOption; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link ByteBufTableImpl}. - */ -public class ByteBufTableImplTest { - - private PTable pTable; - private ByteBuf key; - private ByteBuf value; - private ByteBufTableImpl table; - private OptionFactory optionFactory; - - @SuppressWarnings("unchecked") - @Before - public void setup() { - pTable = mock(PTable.class); - key = Unpooled.wrappedBuffer("test-key".getBytes(UTF_8)); - value = Unpooled.wrappedBuffer("test-value".getBytes(UTF_8)); - table = new ByteBufTableImpl(pTable); - optionFactory = new OptionFactoryImpl<>(); - } - - @Test - public void testGet() { - try (RangeOption option = optionFactory.newRangeOption().build()) { - table.get(key, option); - verify(pTable, times(1)) - .get(same(key), same(key), same(option)); - } - } - - @Test - public void testPut() { - try (PutOption option = optionFactory.newPutOption().build()) { - table.put(key, value, option); - verify(pTable, times(1)) - .put(same(key), same(key), same(value), same(option)); - } - } - - @Test - public void testDelete() { - try (DeleteOption option = optionFactory.newDeleteOption().build()) { - table.delete(key, option); - verify(pTable, times(1)) - .delete(same(key), same(key), same(option)); - } - } - - @Test - public void testIncrement() { - try (IncrementOption option = optionFactory.newIncrementOption().build()) { - table.increment(key, 100L, option); - verify(pTable, times(1)) - .increment(same(key), same(key), eq(100L), same(option)); - } - } - - @Test - public void testTxn() { - table.txn(key); - verify(pTable, times(1)).txn(same(key)); - } - - @Test - public void testOpFactory() { - table.opFactory(); - verify(pTable, times(1)).opFactory(); - } - - @Test - public void testClose() { - table.close(); - verify(pTable, times(1)).close(); - } - -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java deleted file mode 100644 index 8b01b9b3e7e..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Cleanup; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel; -import org.apache.bookkeeper.clients.utils.ClientConstants; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Unit test of {@link DeleteRequestProcessor}. - */ -public class DeleteRequestProcessorTest extends GrpcClientTestBase { - - @Override - protected void doSetup() throws Exception { - } - - @Override - protected void doTeardown() throws Exception { - } - - protected DeleteRangeResponse newSuccessResponse() { - return DeleteRangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .build()) - .build(); - } - - protected DeleteRangeRequest newRequest() { - return DeleteRangeRequest.newBuilder() - .build(); - } - - @Test - public void testProcess() throws Exception { - @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); - - StorageContainerChannel scChannel = mock(StorageContainerChannel.class); - - CompletableFuture serverChannelFuture = FutureUtils.createFuture(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture); - - DeleteRangeResponse response = newSuccessResponse(); - - AtomicReference receivedRequest = new AtomicReference<>(null); - TableServiceImplBase tableService = new TableServiceImplBase() { - - @Override - public void delete(DeleteRangeRequest request, - StreamObserver responseObserver) { - receivedRequest.set(request); - complete(responseObserver); - } - - private void complete(StreamObserver responseStreamObserver) { - responseStreamObserver.onNext(response); - responseStreamObserver.onCompleted(); - } - }; - serviceRegistry.addService(tableService.bindService()); - StorageServerChannel ssChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serverChannelFuture.complete(ssChannel); - - DeleteRangeRequest request = newRequest(); - - DeleteRequestProcessor processor = DeleteRequestProcessor.of( - request, - resp -> "test", - scChannel, - scheduler, - ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY); - assertEquals("test", FutureUtils.result(processor.process())); - assertSame(request, receivedRequest.get()); - } - -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java deleted file mode 100644 index 1b1ec493397..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Cleanup; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel; -import org.apache.bookkeeper.clients.utils.ClientConstants; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Unit test of {@link IncrementRequestProcessor}. - */ -public class IncrementRequestProcessorTest extends GrpcClientTestBase { - - @Override - protected void doSetup() throws Exception { - } - - @Override - protected void doTeardown() throws Exception { - } - - protected IncrementResponse newSuccessResponse() { - return IncrementResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .build()) - .build(); - } - - protected IncrementRequest newRequest() { - return IncrementRequest.newBuilder() - .build(); - } - - @Test - public void testProcess() throws Exception { - @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); - - StorageContainerChannel scChannel = mock(StorageContainerChannel.class); - - CompletableFuture serverChannelFuture = FutureUtils.createFuture(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture); - - IncrementResponse response = newSuccessResponse(); - - AtomicReference receivedRequest = new AtomicReference<>(null); - TableServiceImplBase tableService = new TableServiceImplBase() { - - @Override - public void increment(IncrementRequest request, - StreamObserver responseObserver) { - receivedRequest.set(request); - complete(responseObserver); - } - - private void complete(StreamObserver responseStreamObserver) { - responseStreamObserver.onNext(response); - responseStreamObserver.onCompleted(); - } - }; - serviceRegistry.addService(tableService.bindService()); - StorageServerChannel ssChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serverChannelFuture.complete(ssChannel); - - IncrementRequest request = newRequest(); - - IncrementRequestProcessor processor = IncrementRequestProcessor.of( - request, - resp -> "test", - scChannel, - scheduler, - ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY); - assertEquals("test", FutureUtils.result(processor.process())); - assertSame(request, receivedRequest.get()); - } - -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java deleted file mode 100644 index 3481a26b938..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Cleanup; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel; -import org.apache.bookkeeper.clients.utils.ClientConstants; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Unit test of {@link PutRequestProcessor}. - */ -public class PutRequestProcessorTest extends GrpcClientTestBase { - - @Override - protected void doSetup() throws Exception { - } - - @Override - protected void doTeardown() throws Exception { - } - - protected PutResponse newSuccessResponse() { - return PutResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .build()) - .build(); - } - - protected PutRequest newRequest() { - return PutRequest.newBuilder() - .build(); - } - - @Test - public void testProcess() throws Exception { - @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); - - StorageContainerChannel scChannel = mock(StorageContainerChannel.class); - - CompletableFuture serverChannelFuture = FutureUtils.createFuture(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture); - - PutResponse response = newSuccessResponse(); - - AtomicReference receivedRequest = new AtomicReference<>(null); - TableServiceImplBase tableService = new TableServiceImplBase() { - - @Override - public void put(PutRequest request, - StreamObserver responseObserver) { - receivedRequest.set(request); - complete(responseObserver); - } - - private void complete(StreamObserver responseStreamObserver) { - responseStreamObserver.onNext(response); - responseStreamObserver.onCompleted(); - } - }; - serviceRegistry.addService(tableService.bindService()); - StorageServerChannel ssChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serverChannelFuture.complete(ssChannel); - - PutRequest request = newRequest(); - - PutRequestProcessor processor = PutRequestProcessor.of( - request, - resp -> "test", - scChannel, - scheduler, - ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY); - assertEquals("test", FutureUtils.result(processor.process())); - assertSame(request, receivedRequest.get()); - } - -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java deleted file mode 100644 index 9e53df7f329..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Cleanup; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel; -import org.apache.bookkeeper.clients.utils.ClientConstants; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Unit test of {@link RangeRequestProcessor}. - */ -public class RangeRequestProcessorTest extends GrpcClientTestBase { - - @Override - protected void doSetup() throws Exception { - } - - @Override - protected void doTeardown() throws Exception { - } - - protected RangeResponse newSuccessResponse() { - return RangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .build()) - .build(); - } - - protected RangeRequest newRequest() { - return RangeRequest.newBuilder() - .build(); - } - - @Test - public void testProcess() throws Exception { - @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); - - StorageContainerChannel scChannel = mock(StorageContainerChannel.class); - - CompletableFuture serverChannelFuture = FutureUtils.createFuture(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture); - - RangeResponse response = newSuccessResponse(); - - AtomicReference receivedRequest = new AtomicReference<>(null); - TableServiceImplBase tableService = new TableServiceImplBase() { - - @Override - public void range(RangeRequest request, - StreamObserver responseObserver) { - receivedRequest.set(request); - complete(responseObserver); - } - - private void complete(StreamObserver responseStreamObserver) { - responseStreamObserver.onNext(response); - responseStreamObserver.onCompleted(); - } - }; - serviceRegistry.addService(tableService.bindService()); - StorageServerChannel ssChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serverChannelFuture.complete(ssChannel); - - RangeRequest request = newRequest(); - - RangeRequestProcessor processor = RangeRequestProcessor.of( - request, - resp -> "test", - scChannel, - scheduler, - ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY); - assertEquals("test", FutureUtils.result(processor.process())); - assertSame(request, receivedRequest.get()); - } - -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java deleted file mode 100644 index 50887ac7ae4..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.clients.impl.kv; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newDeleteRequest; -import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newIncrementRequest; -import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newPutRequest; -import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newRangeRequest; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.protobuf.ByteString; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.apache.bookkeeper.api.kv.impl.options.OptionFactoryImpl; -import org.apache.bookkeeper.api.kv.options.DeleteOption; -import org.apache.bookkeeper.api.kv.options.IncrementOption; -import org.apache.bookkeeper.api.kv.options.OptionFactory; -import org.apache.bookkeeper.api.kv.options.Options; -import org.apache.bookkeeper.api.kv.options.PutOption; -import org.apache.bookkeeper.api.kv.options.RangeOption; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest; -import org.junit.Test; - -/** - * Unit test for {@link KvUtils}. - */ -public class TestKvUtils { - - private static final long scId = System.currentTimeMillis(); - private static final ByteString routingKey = ByteString.copyFrom("test-routing-key", UTF_8); - private static final ByteBuf key = Unpooled.wrappedBuffer("test-key".getBytes(UTF_8)); - private static final ByteBuf value = Unpooled.wrappedBuffer("test-value".getBytes(UTF_8)); - private static final ByteString keyBs = ByteString.copyFrom("test-key".getBytes(UTF_8)); - private static final ByteString valueBs = ByteString.copyFrom("test-value".getBytes(UTF_8)); - - private final OptionFactory optionFactory = new OptionFactoryImpl<>(); - - @Test - public void testNewRangeRequest() { - try (RangeOption rangeOption = optionFactory.newRangeOption() - .endKey(key.retainedDuplicate()) - .countOnly(true) - .keysOnly(true) - .limit(10) - .maxCreateRev(1234L) - .minCreateRev(234L) - .maxModRev(2345L) - .minModRev(1235L) - .build()) { - RangeRequest rr = newRangeRequest(key, rangeOption).build(); - assertEquals(keyBs, rr.getKey()); - assertEquals(keyBs, rr.getRangeEnd()); - assertTrue(rr.getCountOnly()); - assertTrue(rr.getKeysOnly()); - assertEquals(10, rr.getLimit()); - assertEquals(1234L, rr.getMaxCreateRevision()); - assertEquals(234L, rr.getMinCreateRevision()); - assertEquals(2345L, rr.getMaxModRevision()); - assertEquals(1235L, rr.getMinModRevision()); - assertFalse(rr.hasHeader()); - } - } - - @Test - public void testNewPutRequest() { - try (PutOption option = Options.putAndGet()) { - PutRequest rr = newPutRequest(key, value, option).build(); - assertEquals(keyBs, rr.getKey()); - assertEquals(valueBs, rr.getValue()); - assertTrue(rr.getPrevKv()); - assertFalse(rr.hasHeader()); - } - } - - @Test - public void testNewIncrementRequest() { - try (IncrementOption option = Options.incrementAndGet()) { - IncrementRequest rr = newIncrementRequest(key, 100L, option).build(); - assertEquals(keyBs, rr.getKey()); - assertEquals(100L, rr.getAmount()); - assertTrue(rr.getGetTotal()); - assertFalse(rr.hasHeader()); - } - } - - @Test - public void testNewDeleteRequest() { - try (DeleteOption option = optionFactory.newDeleteOption() - .endKey(key.retainedDuplicate()) - .prevKv(true) - .build()) { - DeleteRangeRequest rr = newDeleteRequest(key, option).build(); - assertEquals(keyBs, rr.getKey()); - assertEquals(keyBs, rr.getRangeEnd()); - assertTrue(rr.getPrevKv()); - assertFalse(rr.hasHeader()); - } - } - -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestPByteBufTableImpl.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestPByteBufTableImpl.java deleted file mode 100644 index d25c3c93540..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestPByteBufTableImpl.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.clients.impl.kv; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import java.util.List; -import java.util.NavigableMap; -import java.util.Optional; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ThreadLocalRandom; -import org.apache.bookkeeper.api.kv.PTable; -import org.apache.bookkeeper.api.kv.Txn; -import org.apache.bookkeeper.api.kv.impl.options.OptionFactoryImpl; -import org.apache.bookkeeper.api.kv.options.DeleteOption; -import org.apache.bookkeeper.api.kv.options.IncrementOption; -import org.apache.bookkeeper.api.kv.options.OptionFactory; -import org.apache.bookkeeper.api.kv.options.PutOption; -import org.apache.bookkeeper.api.kv.options.RangeOption; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.impl.internal.api.HashStreamRanges; -import org.apache.bookkeeper.clients.impl.internal.api.MetaRangeClient; -import org.apache.bookkeeper.clients.impl.internal.api.StorageServerClientManager; -import org.apache.bookkeeper.clients.impl.routing.RangeRouter; -import org.apache.bookkeeper.clients.utils.ClientConstants; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.router.HashRouter; -import org.apache.bookkeeper.common.util.Bytes; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stream.proto.RangeKeyType; -import org.apache.bookkeeper.stream.proto.RangeProperties; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.protocol.util.ProtoUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test for {@link PByteBufTableImpl}. - */ -public class TestPByteBufTableImpl { - - private static final long streamId = 12345L; - - @Rule - public TestName runtime = new TestName(); - - private final HashStreamRanges streamRanges1 = prepareRanges(streamId, 4, 0); - private final HashStreamRanges streamRanges2 = prepareRanges(streamId, 8, 4L); - private final HashStreamRanges streamRanges3 = prepareRanges(streamId, 80, 12L); - private final HashRouter router = new HashRouter() { - - private static final long serialVersionUID = -9119055960554608491L; - - private final List keys = Lists.newArrayList(streamRanges3.getRanges().keySet()); - - @Override - public Long getRoutingKey(Integer key) { - int idx; - if (null == key) { - idx = ThreadLocalRandom.current().nextInt(keys.size()); - } else { - idx = key % keys.size(); - } - return keys.get(idx); - } - }; - private final StreamProperties streamProps = StreamProperties.newBuilder() - .setStorageContainerId(12345L) - .setStreamConf(DEFAULT_STREAM_CONF) - .setStreamId(streamId) - .setStreamName("test-stream") - .build(); - private final MetaRangeClient mockMetaRangeClient = mock(MetaRangeClient.class); - private final StorageServerClientManager mockClientManager = mock(StorageServerClientManager.class); - private final OptionFactory optionFactory = new OptionFactoryImpl<>(); - - private OrderedScheduler scheduler; - - private static HashStreamRanges prepareRanges(long streamId, int numRanges, long nextRangeId) { - List ranges = ProtoUtils.split(streamId, numRanges, nextRangeId, (sid, rid) -> 1L); - NavigableMap rangeMap = Maps.newTreeMap(); - for (RangeProperties props : ranges) { - rangeMap.put(props.getStartHashKey(), props); - } - return HashStreamRanges.ofHash( - RangeKeyType.HASH, - rangeMap); - } - - @Before - public void setUp() { - when(mockClientManager.openMetaRangeClient(any(StreamProperties.class))) - .thenReturn(mockMetaRangeClient); - scheduler = OrderedScheduler.newSchedulerBuilder() - .numThreads(1) - .name("test-scheduler") - .build(); - } - - @Test - public void testInitializeFailureOnGetActiveRanges() { - ClientException cause = new ClientException("test-cause"); - when(mockMetaRangeClient.getActiveDataRanges()) - .thenReturn(FutureUtils.exception(cause)); - - PByteBufTableImpl table = new PByteBufTableImpl( - runtime.getMethodName(), - streamProps, - mockClientManager, - scheduler.chooseThread(1), - ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY); - try { - FutureUtils.result(table.initialize()); - fail("Should fail initializing the table with exception " + cause); - } catch (Exception e) { - assertEquals(cause, e); - } - } - - @SuppressWarnings("unchecked") - @Test - public void testBasicOperations() throws Exception { - when(mockMetaRangeClient.getActiveDataRanges()) - .thenReturn(FutureUtils.value(streamRanges1)); - - ConcurrentMap> tableRanges = Maps.newConcurrentMap(); - for (RangeProperties rangeProps : streamRanges1.getRanges().values()) { - tableRanges.put(rangeProps.getRangeId(), mock(PTable.class)); - } - - RangeRouter mockRouter = mock(RangeRouter.class); - when(mockRouter.getRange(any(ByteBuf.class))) - .thenAnswer(invocationOnMock -> { - ByteBuf key = invocationOnMock.getArgument(0); - byte[] keyData = ByteBufUtil.getBytes(key); - return Bytes.toLong(keyData, 0); - }); - - TableRangeFactory trFactory = - (streamProps1, rangeProps, executor, opFactory, resultFactory, kvFactory) - -> tableRanges.get(rangeProps.getRangeId()); - PByteBufTableImpl table = new PByteBufTableImpl( - runtime.getMethodName(), - streamProps, - mockClientManager, - scheduler.chooseThread(), - trFactory, - Optional.of(mockRouter)); - assertEquals(0, table.getTableRanges().size()); - verify(mockRouter, times(0)).setRanges(any(HashStreamRanges.class)); - - // initialize the table - assertTrue(table == FutureUtils.result(table.initialize())); - verify(mockRouter, times(1)).setRanges(eq(streamRanges1)); - assertEquals(4, table.getTableRanges().size()); - - // test get - for (RangeProperties rangeProps : streamRanges1.getRanges().values()) { - ByteBuf pkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - ByteBuf lkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - try (RangeOption option = optionFactory.newRangeOption().build()) { - table.get(pkey, lkey, option); - verify(tableRanges.get(rangeProps.getRangeId()), times(1)) - .get(eq(pkey), eq(lkey), eq(option)); - } - } - - // test put - for (RangeProperties rangeProps : streamRanges1.getRanges().values()) { - ByteBuf pkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - ByteBuf lkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - ByteBuf value = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - try (PutOption option = optionFactory.newPutOption().build()) { - table.put(pkey, lkey, value, option); - verify(tableRanges.get(rangeProps.getRangeId()), times(1)) - .put(eq(pkey), eq(lkey), eq(value), eq(option)); - } - } - - // test increment - for (RangeProperties rangeProps : streamRanges1.getRanges().values()) { - ByteBuf pkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - ByteBuf lkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - long amount = 100L; - try (IncrementOption option = optionFactory.newIncrementOption().build()) { - table.increment(pkey, lkey, amount, option); - verify(tableRanges.get(rangeProps.getRangeId()), times(1)) - .increment(eq(pkey), eq(lkey), eq(amount), same(option)); - } - } - - // test delete - for (RangeProperties rangeProps : streamRanges1.getRanges().values()) { - ByteBuf pkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - ByteBuf lkey = - Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - try (DeleteOption option = optionFactory.newDeleteOption().build()) { - table.delete(pkey, lkey, option); - verify(tableRanges.get(rangeProps.getRangeId()), times(1)) - .delete(eq(pkey), eq(lkey), eq(option)); - } - } - - // test txn - for (RangeProperties rangeProps : streamRanges1.getRanges().values()) { - ByteBuf pkey = Unpooled.wrappedBuffer(Bytes.toBytes(rangeProps.getRangeId())); - Txn txn = table.txn(pkey); - verify(tableRanges.get(rangeProps.getRangeId()), times(1)) - .txn(eq(pkey)); - } - } -} diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java deleted file mode 100644 index 2efecd0e373..00000000000 --- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.clients.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Cleanup; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel; -import org.apache.bookkeeper.clients.utils.ClientConstants; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Unit test of {@link TxnRequestProcessor}. - */ -public class TxnRequestProcessorTest extends GrpcClientTestBase { - - @Override - protected void doSetup() throws Exception { - } - - @Override - protected void doTeardown() throws Exception { - } - - protected TxnResponse newSuccessResponse() { - return TxnResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .build()) - .build(); - } - - protected TxnRequest newRequest() { - return TxnRequest.newBuilder() - .build(); - } - - @Test - public void testProcess() throws Exception { - @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); - - StorageContainerChannel scChannel = mock(StorageContainerChannel.class); - - CompletableFuture serverChannelFuture = FutureUtils.createFuture(); - when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture); - - TxnResponse response = newSuccessResponse(); - - AtomicReference receivedRequest = new AtomicReference<>(null); - TableServiceImplBase tableService = new TableServiceImplBase() { - - @Override - public void txn(TxnRequest request, - StreamObserver responseObserver) { - receivedRequest.set(request); - complete(responseObserver); - } - - private void complete(StreamObserver responseStreamObserver) { - responseStreamObserver.onNext(response); - responseStreamObserver.onCompleted(); - } - }; - serviceRegistry.addService(tableService.bindService()); - StorageServerChannel ssChannel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty()); - serverChannelFuture.complete(ssChannel); - - TxnRequest request = newRequest(); - - TxnRequestProcessor processor = TxnRequestProcessor.of( - request, - resp -> "test", - scChannel, - scheduler, - ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY); - assertEquals("test", FutureUtils.result(processor.process())); - assertSame(request, receivedRequest.get()); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/CoderBasicTestCase.java b/stream/common/src/test/java/org/apache/bookkeeper/common/coder/CoderBasicTestCase.java deleted file mode 100644 index 6235234b713..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/CoderBasicTestCase.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.coder; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -/** - * Basic Test Case for {@link Coder}s. - */ -public abstract class CoderBasicTestCase { - - static byte[] encode(Coder coder, T value) { - return coder.encode(value); - } - - static T decode(Coder coder, byte[] bytes) { - ByteBuf buf = Unpooled.wrappedBuffer(bytes); - buf.setIndex(0, bytes.length); - return coder.decode(buf); - } - - private static T decodeEncode(Coder coder, T value) { - byte[] data = encode(coder, value); - assertEquals(coder.getSerializedSize(value), data.length); - return decode(coder, data); - } - - public static void coderDecodeEncodeEqual(Coder coder, T value) { - assertThat(decodeEncode(coder, value), equalTo(value)); - } -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestByteArrayCoder.java b/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestByteArrayCoder.java deleted file mode 100644 index 6ab8d0c4a07..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestByteArrayCoder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.coder; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; - -import java.util.Arrays; -import java.util.List; -import org.junit.Test; - -/** - * Unit tests for {@link ByteArrayCoder}. - */ -public class TestByteArrayCoder extends CoderBasicTestCase { - - private static final ByteArrayCoder TEST_CODER = ByteArrayCoder.of(); - - private static final List TEST_VALUES = Arrays.asList( - new byte[]{0xa, 0xb, 0xc}, - new byte[]{0xd, 0x3}, - new byte[]{0xd, 0xe}, - new byte[]{}); - - @Test - public void testDecodeEncodeEquals() throws Exception { - for (byte[] value : TEST_VALUES) { - coderDecodeEncodeEqual(TEST_CODER, value); - } - } - - @Test - public void testEncodeThenMutate() throws Exception { - byte[] input = {0x7, 0x3, 0xA, 0xf}; - byte[] encoded = encode(TEST_CODER, input); - input[1] = 0x9; - byte[] decoded = decode(TEST_CODER, encoded); - - // byte array coder that does encoding/decoding without copying - // the bytes, so mutating the input will mutate the output - assertThat(input, equalTo(decoded)); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestStringUtf8Coder.java b/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestStringUtf8Coder.java deleted file mode 100644 index a5545460ffe..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestStringUtf8Coder.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.coder; - -import java.util.Arrays; -import java.util.List; -import org.junit.Test; - -/** - * Unit Tests for {@link StringUtf8Coder}. - */ -public class TestStringUtf8Coder extends CoderBasicTestCase { - - private static final Coder TEST_CODER = StringUtf8Coder.of(); - - private static final List TEST_VALUES = Arrays.asList( - "", "a", "13", "hello", - "a longer string with spaces and all that", - "a string with a \n newline", - "スタリング"); - - @Test - public void testDecodeEncodeEquals() throws Exception { - for (String value : TEST_VALUES) { - coderDecodeEncodeEqual(TEST_CODER, value); - } - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestVarIntCoder.java b/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestVarIntCoder.java deleted file mode 100644 index 9ce7437e6e9..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/coder/TestVarIntCoder.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.coder; - -import java.util.Arrays; -import java.util.List; -import org.junit.Test; - -/** - * Unit Tests for {@link VarIntCoder}. - */ -public class TestVarIntCoder extends CoderBasicTestCase { - - private static final Coder TEST_CODER = VarIntCoder.of(); - - private static final List TEST_VALUES = Arrays.asList( - -11, -3, -1, 0, 1, 5, 13, 29, - Integer.MAX_VALUE, - Integer.MIN_VALUE); - - @Test - public void testDecodeEncodeEquals() throws Exception { - for (Integer value : TEST_VALUES) { - coderDecodeEncodeEqual(TEST_CODER, value); - } - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityBinaryMarshallerTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityBinaryMarshallerTest.java deleted file mode 100644 index 730cc6f0d7e..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityBinaryMarshallerTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.netty; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertSame; - -import java.util.concurrent.ThreadLocalRandom; -import org.junit.Test; - -/** - * Unit test {@link IdentityBinaryMarshaller}. - */ -public class IdentityBinaryMarshallerTest { - - @Test - public void testParseAndToBytes() { - byte[] data = new byte[32]; - ThreadLocalRandom.current().nextBytes(data); - byte[] dataCopy = new byte[data.length]; - System.arraycopy(data, 0, dataCopy, 0, data.length); - - byte[] serializedData = IdentityBinaryMarshaller.of().toBytes(data); - // identity binary marshaller should return same object - assertSame(data, serializedData); - // identity binary marshaller should return same content - assertArrayEquals(dataCopy, serializedData); - - byte[] deserializedData = IdentityBinaryMarshaller.of().parseBytes(data); - // identity binary marshaller should return same object - assertSame(data, deserializedData); - // identity binary marshaller should return same content - assertArrayEquals(dataCopy, deserializedData); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityInputStreamMarshallerTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityInputStreamMarshallerTest.java deleted file mode 100644 index 8cafc2f5f17..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/IdentityInputStreamMarshallerTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.netty; - -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; - -import java.io.InputStream; -import org.junit.Test; - -/** - * Unit test {@link IdentityInputStreamMarshaller}. - */ -public class IdentityInputStreamMarshallerTest { - - @Test - public void testStream() { - InputStream mockIs = mock(InputStream.class); - assertSame(mockIs, IdentityInputStreamMarshaller.of().stream(mockIs)); - } - - @Test - public void testParse() { - InputStream mockIs = mock(InputStream.class); - assertSame(mockIs, IdentityInputStreamMarshaller.of().parse(mockIs)); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/LongBinaryMarshallerTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/LongBinaryMarshallerTest.java deleted file mode 100644 index e4dccb54ee4..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/netty/LongBinaryMarshallerTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.netty; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import org.apache.bookkeeper.common.util.Bytes; -import org.junit.Test; - -/** - * Unit test {@link LongBinaryMarshaller}. - */ -public class LongBinaryMarshallerTest { - - @Test - public void testParseAndToBytes() { - long value = System.currentTimeMillis(); - byte[] valueBytes = LongBinaryMarshaller.of().toBytes(value); - assertArrayEquals(Bytes.toBytes(value), valueBytes); - long parsedValue = LongBinaryMarshaller.of().parseBytes(valueBytes); - assertEquals(value, parsedValue); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/DirectPingPongServiceTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/DirectPingPongServiceTest.java deleted file mode 100644 index 4611efea427..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/DirectPingPongServiceTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.proxy; - -/** - * Test PingPongService by directly accessing the grpc service. - * - *

This is to ensure the tests in {@link PingPongServiceTestBase} are correct to be used for testing - * reverse proxy in {@link ProxyPingPongServiceTest}. - */ -public class DirectPingPongServiceTest extends PingPongServiceTestBase { - public DirectPingPongServiceTest() { - super(false); - } -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java deleted file mode 100644 index 6f7da168962..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.proxy; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import io.grpc.ManagedChannel; -import io.grpc.Server; -import io.grpc.ServerServiceDefinition; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.stub.StreamObserver; -import io.grpc.util.MutableHandlerRegistry; -import java.util.Iterator; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.IntStream; -import lombok.Data; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.ExceptionalFunction; -import org.apache.bookkeeper.tests.rpc.PingPongService; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc.PingPongServiceBlockingStub; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc.PingPongServiceStub; -import org.bookkeeper.tests.proto.rpc.PingRequest; -import org.bookkeeper.tests.proto.rpc.PongResponse; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Test grpc reverse proxy using {@link org.apache.bookkeeper.tests.rpc.PingPongService}. - */ -public abstract class PingPongServiceTestBase { - - private static final int NUM_PONGS_PER_PING = 10; - private static final String SERVICE_NAME = "pingpong"; - - private final boolean useReverseProxy; - - protected Server realServer; - protected Server proxyServer; - protected PingPongService service; - protected ManagedChannel proxyChannel; - protected ManagedChannel clientChannel; - protected PingPongServiceStub client; - - PingPongServiceTestBase(boolean useReverseProxy) { - this.useReverseProxy = useReverseProxy; - } - - @Before - public void setup() throws Exception { - service = new PingPongService(NUM_PONGS_PER_PING); - ServerServiceDefinition pingPongServiceDef = service.bindService(); - - String serverName; - if (useReverseProxy) { - serverName = "proxy-" + SERVICE_NAME; - } else { - serverName = SERVICE_NAME; - } - // build a real server - MutableHandlerRegistry realRegistry = new MutableHandlerRegistry(); - realServer = InProcessServerBuilder - .forName(serverName) - .fallbackHandlerRegistry(realRegistry) - .directExecutor() - .build() - .start(); - realRegistry.addService(pingPongServiceDef); - - if (useReverseProxy) { - proxyChannel = InProcessChannelBuilder.forName(serverName) - .usePlaintext() - .build(); - - ProxyHandlerRegistry registry = ProxyHandlerRegistry.newBuilder() - .addService(pingPongServiceDef) - .setChannelFinder((serverCall, header) -> proxyChannel) - .build(); - proxyServer = InProcessServerBuilder - .forName(SERVICE_NAME) - .fallbackHandlerRegistry(registry) - .directExecutor() - .build() - .start(); - } else { - proxyServer = realServer; - } - - clientChannel = InProcessChannelBuilder.forName(SERVICE_NAME) - .usePlaintext() - .build(); - - client = PingPongServiceGrpc.newStub(clientChannel); - - } - - @After - public void teardown() throws Exception { - if (null != clientChannel) { - clientChannel.shutdown(); - } - - if (null != proxyServer) { - proxyServer.shutdown(); - } - - if (null != proxyChannel) { - proxyChannel.shutdown(); - } - - if (null != realServer && proxyServer != realServer) { - realServer.shutdown(); - } - } - - - @Test - public void testUnary() { - PingPongServiceBlockingStub clientBlocking = PingPongServiceGrpc.newBlockingStub(clientChannel); - - long sequence = ThreadLocalRandom.current().nextLong(); - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence) - .build(); - PongResponse response = clientBlocking.pingPong(request); - assertEquals(sequence, response.getLastSequence()); - assertEquals(1, response.getNumPingReceived()); - assertEquals(0, response.getSlotId()); - } - - @Test - public void testServerStreaming() { - PingPongServiceBlockingStub clientBlocking = PingPongServiceGrpc.newBlockingStub(clientChannel); - - long sequence = ThreadLocalRandom.current().nextLong(100000); - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence) - .build(); - Iterator respIter = clientBlocking.lotsOfPongs(request); - int count = 0; - while (respIter.hasNext()) { - PongResponse resp = respIter.next(); - assertEquals(sequence, resp.getLastSequence()); - assertEquals(1, resp.getNumPingReceived()); - assertEquals(count, resp.getSlotId()); - ++count; - } - } - - @Test - public void testClientStreaming() throws Exception { - final int numPings = 100; - final long sequence = ThreadLocalRandom.current().nextLong(100000); - final CompletableFuture respFuture = new CompletableFuture<>(); - final LinkedBlockingQueue respQueue = new LinkedBlockingQueue<>(); - StreamObserver pinger = client.lotsOfPings(new StreamObserver() { - @Override - public void onNext(PongResponse resp) { - respQueue.offer(resp); - } - - @Override - public void onError(Throwable t) { - respFuture.completeExceptionally(t); - } - - @Override - public void onCompleted() { - FutureUtils.complete(respFuture, null); - } - }); - - for (int i = 0; i < numPings; i++) { - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence + i) - .build(); - pinger.onNext(request); - } - pinger.onCompleted(); - - // wait for response to be received. - result(respFuture); - - assertEquals(1, respQueue.size()); - - PongResponse resp = respQueue.take(); - assertEquals(sequence + numPings - 1, resp.getLastSequence()); - assertEquals(numPings, resp.getNumPingReceived()); - assertEquals(0, resp.getSlotId()); - } - - @Test - public void testBidiStreaming() throws Exception { - final int numPings = 100; - - final CompletableFuture respFuture = new CompletableFuture<>(); - final LinkedBlockingQueue respQueue = new LinkedBlockingQueue<>(); - StreamObserver pinger = client.bidiPingPong(new StreamObserver() { - @Override - public void onNext(PongResponse resp) { - respQueue.offer(resp); - } - - @Override - public void onError(Throwable t) { - respFuture.completeExceptionally(t); - } - - @Override - public void onCompleted() { - FutureUtils.complete(respFuture, null); - } - }); - - final LinkedBlockingQueue reqQueue = new LinkedBlockingQueue<>(); - for (int i = 0; i < numPings; i++) { - final long sequence = ThreadLocalRandom.current().nextLong(100000); - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence) - .build(); - reqQueue.put(request); - pinger.onNext(request); - } - pinger.onCompleted(); - - // wait for response to be received - result(respFuture); - - assertEquals(numPings, respQueue.size()); - - int count = 0; - for (PingRequest request : reqQueue) { - PongResponse response = respQueue.take(); - - assertEquals(request.getSequence(), response.getLastSequence()); - assertEquals(++count, response.getNumPingReceived()); - assertEquals(0, response.getSlotId()); - } - assertNull(respQueue.poll()); - assertEquals(numPings, count); - } - - @Data - static class Runner implements Runnable { - - private final CountDownLatch startLatch; - private final CountDownLatch doneLatch; - private final AtomicReference exceptionHolder; - private final ExceptionalFunction func; - - @Override - public void run() { - try { - startLatch.await(); - } catch (InterruptedException e) { - } - int numIters = ThreadLocalRandom.current().nextInt(10, 100); - IntStream.of(numIters).forEach(idx -> { - if (null != exceptionHolder.get()) { - // break if exception occurs - return; - } - try { - func.apply(null); - } catch (Exception e) { - exceptionHolder.set(e); - doneLatch.countDown(); - } - }); - if (null == exceptionHolder.get()) { - doneLatch.countDown(); - } - } - } - - @Test - public void testMixed() throws Exception { - int numTypes = 4; - - final CountDownLatch startLatch = new CountDownLatch(1); - final CountDownLatch doneLatch = new CountDownLatch(numTypes); - final AtomicReference exception = new AtomicReference<>(); - - ExecutorService executor = Executors.newFixedThreadPool(numTypes); - // start unmary test - executor.submit(new Runner(startLatch, doneLatch, exception, ignored -> { - testUnary(); - return null; - })); - - // start client streaming tests - executor.submit(new Runner(startLatch, doneLatch, exception, ignored -> { - testClientStreaming(); - return null; - })); - - // start server streaming tests - executor.submit(new Runner(startLatch, doneLatch, exception, ignored -> { - testServerStreaming(); - return null; - })); - - // start bidi streaming tests - executor.submit(new Runner(startLatch, doneLatch, exception, ignored -> { - testBidiStreaming(); - return null; - })); - - // start the tests - startLatch.countDown(); - - // wait for tests to complete - doneLatch.await(); - - // make sure all succeed - assertNull("Exception found : " + exception.get(), exception.get()); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/ProxyPingPongServiceTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/ProxyPingPongServiceTest.java deleted file mode 100644 index a099717cf31..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/ProxyPingPongServiceTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.proxy; - -/** - * Test reverse grpc proxy using ping pong service. - */ -public class ProxyPingPongServiceTest extends PingPongServiceTestBase { - - public ProxyPingPongServiceTest() { - super(true); - } -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ClientStatsTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ClientStatsTest.java deleted file mode 100644 index d5cf2d356a9..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ClientStatsTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.stats; - -import static org.junit.Assert.assertEquals; - -import io.grpc.MethodDescriptor; -import io.grpc.Status; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.common.grpc.stats.ClientStats.Factory; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link ClientStats}. - */ -public class ClientStatsTest { - - private Factory factoryWithHistograms; - private Factory factoryWithoutHistograms; - private TestStatsProvider statsProvider; - - @Before - public void setup() { - this.statsProvider = new TestStatsProvider(); - this.factoryWithHistograms = new Factory(true); - this.factoryWithoutHistograms = new Factory(false); - } - - @Test - public void testClientStatsWithHistogram() { - testClientStats(factoryWithHistograms, true); - } - - @Test - public void testClientStatsWithoutHistogram() { - testClientStats(factoryWithoutHistograms, false); - } - - private void testClientStats(Factory clientStatsFactory, - boolean includeLatencyHistogram) { - // test unary method - MethodDescriptor unaryMethod = PingPongServiceGrpc.getPingPongMethod(); - testClientStats( - clientStatsFactory, - includeLatencyHistogram, - unaryMethod, - "PingPong", - "unary", - 1, - 1, - 0, - 0 - ); - // test client streaming - MethodDescriptor clientStreamingMethod = PingPongServiceGrpc.getLotsOfPingsMethod(); - testClientStats( - clientStatsFactory, - includeLatencyHistogram, - clientStreamingMethod, - "LotsOfPings", - "client_streaming", - 1, - 1, - 1, - 0 - ); - // test server streaming - MethodDescriptor serverStreamingMethod = PingPongServiceGrpc.getLotsOfPongsMethod(); - testClientStats( - clientStatsFactory, - includeLatencyHistogram, - serverStreamingMethod, - "LotsOfPongs", - "server_streaming", - 1, - 1, - 0, - 2 - ); - // test server streaming - MethodDescriptor biStreamingMethod = PingPongServiceGrpc.getBidiPingPongMethod(); - testClientStats( - clientStatsFactory, - includeLatencyHistogram, - biStreamingMethod, - "BidiPingPong", - "bidi_streaming", - 1, - 1, - 1, - 2 - ); - } - - private void testClientStats(Factory clientStatsFactory, - boolean includeLatencyHistogram, - MethodDescriptor method, - String methodName, - String statsScope, - long expectedCallStarted, - long expectedCallCompleted, - long expectedStreamMsgsSent, - long expectedStreamMsgsReceived) { - StatsLogger statsLogger = statsProvider.getStatsLogger(statsScope); - ClientStats unaryStats = clientStatsFactory.createMetricsForMethod( - method, - statsLogger - ); - unaryStats.recordCallStarted(); - assertEquals( - expectedCallStarted, - statsLogger.scope(methodName).getCounter("grpc_started").get().longValue()); - unaryStats.recordClientHandled(Status.OK.getCode()); - assertEquals( - expectedCallCompleted, - statsLogger.scope(methodName).getCounter("grpc_completed").get().longValue()); - unaryStats.recordStreamMessageSent(); - assertEquals( - expectedStreamMsgsSent, - statsLogger.scope(methodName).getCounter("grpc_msg_sent").get().longValue()); - unaryStats.recordStreamMessageReceived(); - unaryStats.recordStreamMessageReceived(); - assertEquals( - expectedStreamMsgsReceived, - statsLogger.scope(methodName).getCounter("grpc_msg_received").get().longValue()); - long latencyMicros = 12345L; - unaryStats.recordLatency(true, latencyMicros); - TestOpStatsLogger opStatsLogger = - (TestOpStatsLogger) statsLogger.scope(methodName).getOpStatsLogger("grpc_latency_micros"); - if (includeLatencyHistogram) { - assertEquals(1, opStatsLogger.getSuccessCount()); - assertEquals( - TimeUnit.MICROSECONDS.toNanos(latencyMicros), - (long) opStatsLogger.getSuccessAverage()); - } else { - assertEquals(0, opStatsLogger.getSuccessCount()); - assertEquals(0, (long) opStatsLogger.getSuccessAverage()); - } - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/GrpcStatsIntegrationTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/GrpcStatsIntegrationTest.java deleted file mode 100644 index e34f30e1d2d..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/GrpcStatsIntegrationTest.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.stats; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import io.grpc.Channel; -import io.grpc.ClientInterceptors; -import io.grpc.ManagedChannel; -import io.grpc.Server; -import io.grpc.ServerInterceptors; -import io.grpc.ServerServiceDefinition; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.stub.StreamObserver; -import io.grpc.util.MutableHandlerRegistry; -import java.util.Iterator; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadLocalRandom; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger; -import org.apache.bookkeeper.tests.rpc.PingPongService; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc.PingPongServiceBlockingStub; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc.PingPongServiceStub; -import org.bookkeeper.tests.proto.rpc.PingRequest; -import org.bookkeeper.tests.proto.rpc.PongResponse; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * End-to-end integration test on grpc stats. - */ -public class GrpcStatsIntegrationTest { - - private static final int NUM_PONGS_PER_PING = 10; - private static final String SERVICE_NAME = "pingpong"; - - private Server server; - private PingPongService service; - private ManagedChannel channel; - private Channel monitoredChannel; - private PingPongServiceBlockingStub client; - private PingPongServiceStub clientNonBlocking; - private TestStatsProvider statsProvider; - private TestStatsLogger clientStatsLogger; - private TestStatsLogger serverStatsLogger; - - - @Before - public void setup() throws Exception { - statsProvider = new TestStatsProvider(); - clientStatsLogger = statsProvider.getStatsLogger("client"); - serverStatsLogger = statsProvider.getStatsLogger("server"); - service = new PingPongService(NUM_PONGS_PER_PING); - ServerServiceDefinition monitoredService = ServerInterceptors.intercept( - service, - MonitoringServerInterceptor.create(serverStatsLogger, true) - ); - MutableHandlerRegistry registry = new MutableHandlerRegistry(); - server = InProcessServerBuilder - .forName(SERVICE_NAME) - .fallbackHandlerRegistry(registry) - .directExecutor() - .build() - .start(); - registry.addService(monitoredService); - - channel = InProcessChannelBuilder.forName(SERVICE_NAME) - .usePlaintext() - .build(); - monitoredChannel = ClientInterceptors.intercept( - channel, - MonitoringClientInterceptor.create(clientStatsLogger, true) - ); - client = PingPongServiceGrpc.newBlockingStub(monitoredChannel); - clientNonBlocking = PingPongServiceGrpc.newStub(monitoredChannel); - } - - @After - public void teardown() { - if (null != channel) { - channel.shutdown(); - } - if (null != server) { - server.shutdown(); - } - } - - private void assertStats(String methodName, - long numCalls, - long numClientMsgSent, - long numClientMsgReceived, - long numServerMsgSent, - long numServerMsgReceived) { - // client stats - assertEquals( - numCalls, - clientStatsLogger.scope(methodName).getCounter("grpc_started").get().longValue() - ); - assertEquals( - numCalls, - clientStatsLogger.scope(methodName).getCounter("grpc_completed").get().longValue() - ); - assertEquals( - numClientMsgSent, - clientStatsLogger.scope(methodName).getCounter("grpc_msg_sent").get().longValue() - ); - assertEquals( - numClientMsgReceived, - clientStatsLogger.scope(methodName).getCounter("grpc_msg_received").get().longValue() - ); - TestOpStatsLogger opStatsLogger = - (TestOpStatsLogger) clientStatsLogger.scope(methodName).getOpStatsLogger("grpc_latency_micros"); - assertEquals( - numCalls, - opStatsLogger.getSuccessCount() - ); - // server stats - assertEquals( - numCalls, - serverStatsLogger.scope(methodName).getCounter("grpc_started").get().longValue() - ); - assertEquals( - numCalls, - serverStatsLogger.scope(methodName).getCounter("grpc_completed").get().longValue() - ); - assertEquals( - numServerMsgSent, - serverStatsLogger.scope(methodName).getCounter("grpc_msg_sent").get().longValue() - ); - assertEquals( - numServerMsgReceived, - serverStatsLogger.scope(methodName).getCounter("grpc_msg_received").get().longValue() - ); - opStatsLogger = - (TestOpStatsLogger) serverStatsLogger.scope(methodName).getOpStatsLogger("grpc_latency_micros"); - assertEquals( - numCalls, - opStatsLogger.getSuccessCount() - ); - } - - @Test - public void testUnary() { - long sequence = ThreadLocalRandom.current().nextLong(); - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence) - .build(); - PongResponse response = client.pingPong(request); - assertEquals(sequence, response.getLastSequence()); - assertEquals(1, response.getNumPingReceived()); - assertEquals(0, response.getSlotId()); - - // verify the stats - assertStats( - "PingPong", - 1, - 0, - 0, - 0, - 0); - } - - @Test - public void testServerStreaming() { - long sequence = ThreadLocalRandom.current().nextLong(100000); - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence) - .build(); - Iterator respIter = client.lotsOfPongs(request); - int count = 0; - while (respIter.hasNext()) { - PongResponse resp = respIter.next(); - assertEquals(sequence, resp.getLastSequence()); - assertEquals(1, resp.getNumPingReceived()); - assertEquals(count, resp.getSlotId()); - ++count; - } - - assertStats( - "LotsOfPongs", - 1, - 0, - NUM_PONGS_PER_PING, - NUM_PONGS_PER_PING, - 0); - } - - @Test - public void testClientStreaming() throws Exception { - final int numPings = 100; - final long sequence = ThreadLocalRandom.current().nextLong(100000); - final CompletableFuture respFuture = new CompletableFuture<>(); - final LinkedBlockingQueue respQueue = new LinkedBlockingQueue<>(); - StreamObserver pinger = clientNonBlocking.lotsOfPings(new StreamObserver() { - @Override - public void onNext(PongResponse resp) { - respQueue.offer(resp); - } - - @Override - public void onError(Throwable t) { - respFuture.completeExceptionally(t); - } - - @Override - public void onCompleted() { - FutureUtils.complete(respFuture, null); - } - }); - - for (int i = 0; i < numPings; i++) { - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence + i) - .build(); - pinger.onNext(request); - } - pinger.onCompleted(); - - // wait for response to be received. - result(respFuture); - - assertEquals(1, respQueue.size()); - - PongResponse resp = respQueue.take(); - assertEquals(sequence + numPings - 1, resp.getLastSequence()); - assertEquals(numPings, resp.getNumPingReceived()); - assertEquals(0, resp.getSlotId()); - - assertStats( - "LotsOfPings", - 1, - numPings, - 0, - 0, - numPings - ); - } - - @Test - public void testBidiStreaming() throws Exception { - final int numPings = 100; - - final CompletableFuture respFuture = new CompletableFuture<>(); - final LinkedBlockingQueue respQueue = new LinkedBlockingQueue<>(); - StreamObserver pinger = clientNonBlocking.bidiPingPong(new StreamObserver() { - @Override - public void onNext(PongResponse resp) { - respQueue.offer(resp); - } - - @Override - public void onError(Throwable t) { - respFuture.completeExceptionally(t); - } - - @Override - public void onCompleted() { - FutureUtils.complete(respFuture, null); - } - }); - - final LinkedBlockingQueue reqQueue = new LinkedBlockingQueue<>(); - for (int i = 0; i < numPings; i++) { - final long sequence = ThreadLocalRandom.current().nextLong(100000); - PingRequest request = PingRequest.newBuilder() - .setSequence(sequence) - .build(); - reqQueue.put(request); - pinger.onNext(request); - } - pinger.onCompleted(); - - // wait for response to be received - result(respFuture); - - assertEquals(numPings, respQueue.size()); - - int count = 0; - for (PingRequest request : reqQueue) { - PongResponse response = respQueue.take(); - - assertEquals(request.getSequence(), response.getLastSequence()); - assertEquals(++count, response.getNumPingReceived()); - assertEquals(0, response.getSlotId()); - } - assertNull(respQueue.poll()); - assertEquals(numPings, count); - - assertStats( - "BidiPingPong", - 1, - numPings, - numPings, - numPings, - numPings - ); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ServerStatsTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ServerStatsTest.java deleted file mode 100644 index 8300aa6327e..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/stats/ServerStatsTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.grpc.stats; - -import static org.junit.Assert.assertEquals; - -import io.grpc.MethodDescriptor; -import io.grpc.Status; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.common.grpc.stats.ServerStats.Factory; -import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.bookkeeper.test.TestStatsProvider; -import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger; -import org.bookkeeper.tests.proto.rpc.PingPongServiceGrpc; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link ServerStats}. - */ -public class ServerStatsTest { - - private Factory factoryWithHistograms; - private Factory factoryWithoutHistograms; - private TestStatsProvider statsProvider; - - @Before - public void setup() { - this.statsProvider = new TestStatsProvider(); - this.factoryWithHistograms = new Factory(true); - this.factoryWithoutHistograms = new Factory(false); - } - - @Test - public void testServerStatsWithHistogram() { - testServerStats(factoryWithHistograms, true); - } - - @Test - public void testServerStatsWithoutHistogram() { - testServerStats(factoryWithoutHistograms, false); - } - - private void testServerStats(Factory clientStatsFactory, - boolean includeLatencyHistogram) { - // test unary method - MethodDescriptor unaryMethod = PingPongServiceGrpc.getPingPongMethod(); - testServerStats( - clientStatsFactory, - includeLatencyHistogram, - unaryMethod, - "PingPong", - "unary", - 1, - 1, - 0, - 0 - ); - // test client streaming - MethodDescriptor clientStreamingMethod = PingPongServiceGrpc.getLotsOfPingsMethod(); - testServerStats( - clientStatsFactory, - includeLatencyHistogram, - clientStreamingMethod, - "LotsOfPings", - "client_streaming", - 1, - 1, - 0, - 2 - ); - // test server streaming - MethodDescriptor serverStreamingMethod = PingPongServiceGrpc.getLotsOfPongsMethod(); - testServerStats( - clientStatsFactory, - includeLatencyHistogram, - serverStreamingMethod, - "LotsOfPongs", - "server_streaming", - 1, - 1, - 1, - 0 - ); - // test server streaming - MethodDescriptor biStreamingMethod = PingPongServiceGrpc.getBidiPingPongMethod(); - testServerStats( - clientStatsFactory, - includeLatencyHistogram, - biStreamingMethod, - "BidiPingPong", - "bidi_streaming", - 1, - 1, - 1, - 2 - ); - } - - private void testServerStats(Factory clientStatsFactory, - boolean includeLatencyHistogram, - MethodDescriptor method, - String methodName, - String statsScope, - long expectedCallStarted, - long expectedCallCompleted, - long expectedStreamMsgsSent, - long expectedStreamMsgsReceived) { - StatsLogger statsLogger = statsProvider.getStatsLogger(statsScope); - ServerStats unaryStats = clientStatsFactory.createMetricsForMethod( - method, - statsLogger - ); - unaryStats.recordCallStarted(); - assertEquals( - expectedCallStarted, - statsLogger.scope(methodName).getCounter("grpc_started").get().longValue()); - unaryStats.recordServerHandled(Status.OK.getCode()); - assertEquals( - expectedCallCompleted, - statsLogger.scope(methodName).getCounter("grpc_completed").get().longValue()); - unaryStats.recordStreamMessageSent(); - assertEquals( - expectedStreamMsgsSent, - statsLogger.scope(methodName).getCounter("grpc_msg_sent").get().longValue()); - unaryStats.recordStreamMessageReceived(); - unaryStats.recordStreamMessageReceived(); - assertEquals( - expectedStreamMsgsReceived, - statsLogger.scope(methodName).getCounter("grpc_msg_received").get().longValue()); - long latencyMicros = 12345L; - unaryStats.recordLatency(true, latencyMicros); - TestOpStatsLogger opStatsLogger = - (TestOpStatsLogger) statsLogger.scope(methodName).getOpStatsLogger("grpc_latency_micros"); - if (includeLatencyHistogram) { - assertEquals(1, opStatsLogger.getSuccessCount()); - assertEquals( - TimeUnit.MICROSECONDS.toNanos(latencyMicros), - (long) opStatsLogger.getSuccessAverage()); - } else { - assertEquals(0, opStatsLogger.getSuccessCount()); - assertEquals(0, (long) opStatsLogger.getSuccessAverage()); - } - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java b/stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java deleted file mode 100644 index a7814867a56..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.reslover; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - -import com.google.common.collect.Lists; -import io.grpc.Attributes; -import io.grpc.EquivalentAddressGroup; -import java.net.InetSocketAddress; -import java.net.URI; -import java.util.List; -import java.util.stream.Collectors; -import org.apache.bookkeeper.common.resolver.StaticNameResolver; -import org.apache.bookkeeper.common.util.SharedResourceManager.Resource; -import org.junit.Test; - -/** - * Unit test of {@link StaticNameResolver}. - */ -public class TestSimpleNameResolver { - - static List createServers(int numBookies) { - List servers = Lists.newArrayListWithExpectedSize(numBookies); - int basePort = 3181; - for (int i = 0; i < numBookies; i++) { - servers.add(new InetSocketAddress("127.0.0.1", basePort + i)); - } - return servers; - } - - @Test - public void testGetServers() { - List servers = createServers(5); - List uris = servers - .stream() - .map(addr -> URI.create("bookie://" + addr.getHostName() + ":" + addr.getPort())) - .collect(Collectors.toList()); - List resolvedServers = servers - .stream() - .map(addr -> new EquivalentAddressGroup( - Lists.newArrayList(addr), - Attributes.EMPTY)) - .collect(Collectors.toList()); - - @SuppressWarnings("unchecked") // for the mock - StaticNameResolver nameResolver = new StaticNameResolver( - "test-name-resolver", - mock(Resource.class), - uris); - - assertEquals(resolvedServers, nameResolver.getServers()); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/router/HashRouterTest.java b/stream/common/src/test/java/org/apache/bookkeeper/common/router/HashRouterTest.java deleted file mode 100644 index 4f46cb05b1a..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/router/HashRouterTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.common.router; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import com.google.common.hash.Hashing; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.hash.Murmur3; -import org.junit.Test; - -/** - * Unit test {@link HashRouter}s. - */ -@Slf4j -public class HashRouterTest { - - @Test - public void testByteBufHashRouter() { - byte[] keyBytes = "foo".getBytes(UTF_8); - ByteBuf key = Unpooled.wrappedBuffer(keyBytes); - - // murmur3 - 32 bits - int hash32 = Murmur3.hash32( - key, key.readerIndex(), key.readableBytes(), (int) AbstractHashRouter.HASH_SEED); - int bytesHash32 = Murmur3.hash32(keyBytes, 0, keyBytes.length, (int) AbstractHashRouter.HASH_SEED); - int guavaHash32 = Hashing.murmur3_32_fixed((int) AbstractHashRouter.HASH_SEED) - .newHasher() - .putString("foo", UTF_8) - .hash() - .asInt(); - assertEquals(hash32, bytesHash32); - assertEquals(hash32, guavaHash32); - - // murmur3 - 128 bits - long[] hash128 = Murmur3.hash128( - key, key.readerIndex(), key.readableBytes(), AbstractHashRouter.HASH_SEED); - long[] bytesHash128 = Murmur3.hash128(keyBytes, 0, keyBytes.length, AbstractHashRouter.HASH_SEED); - log.info("hash128: {}, bytes hash128: {}", hash128, bytesHash128); - long guavaHash128 = Hashing.murmur3_128((int) AbstractHashRouter.HASH_SEED) - .newHasher() - .putString("foo", UTF_8) - .hash() - .asLong(); - assertArrayEquals(hash128, bytesHash128); - assertEquals(hash128[0], guavaHash128); - - ByteBufHashRouter router = ByteBufHashRouter.of(); - long routingHash = router.getRoutingKey(key); - log.info("Routing hash = {}", routingHash); - assertEquals(hash128[0], routingHash); - BytesHashRouter bytesRouter = BytesHashRouter.of(); - long bytesRoutingHash = bytesRouter.getRoutingKey(keyBytes); - assertEquals(hash128[0], bytesRoutingHash); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestBytes.java b/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestBytes.java deleted file mode 100644 index 5487a6a220c..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestBytes.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -/** - * Unit test for {@link Bytes}. - */ -public class TestBytes { - - @Test - public void testOneNumber() { - long timestamp = System.currentTimeMillis(); - byte[] bytes = Bytes.toBytes(timestamp); - long readTimestamp = Bytes.toLong(bytes, 0); - assertEquals(timestamp, readTimestamp); - } - - @Test - public void testTwoNumbers() { - long timestamp1 = System.currentTimeMillis(); - long timestamp2 = 2 * timestamp1; - byte[] bytes = new byte[16]; - Bytes.toBytes(timestamp1, bytes, 0); - Bytes.toBytes(timestamp2, bytes, 8); - long readTimestamp1 = Bytes.toLong(bytes, 0); - long readTimestamp2 = Bytes.toLong(bytes, 8); - assertEquals(timestamp1, readTimestamp1); - assertEquals(timestamp2, readTimestamp2); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestExceptionUtils.java b/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestExceptionUtils.java deleted file mode 100644 index ee7d0826c59..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestExceptionUtils.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.common.util; - -import static org.apache.bookkeeper.common.util.ExceptionUtils.toIOException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.exceptions.ObjectClosedException; -import org.junit.Test; - -/** - * Test Case for {@link ExceptionUtils}. - */ -public class TestExceptionUtils { - - @Test - public void testCallAndHandleClosedAsync() throws Exception { - String componentName = "test-component"; - CompletableFuture closedFuture = ExceptionUtils.callAndHandleClosedAsync( - componentName, - true, - (future) -> { - future.complete(10L); - }); - try { - FutureUtils.result(closedFuture); - fail("Should fail with object closed exception"); - } catch (ObjectClosedException oce) { - assertEquals(componentName + " is already closed.", oce.getMessage()); - } - - CompletableFuture noneClosedFuture = ExceptionUtils.callAndHandleClosedAsync( - componentName, - false, - (future) -> { - future.complete(10L); - }); - assertEquals(10L, FutureUtils.result(noneClosedFuture).longValue()); - } - - @Test - public void testToIOException() { - IOException ioe = new IOException("Test-IOE"); - assertTrue(ioe == toIOException(ioe)); - Exception se = new Exception("Test-DLSE"); - IOException ioe2 = toIOException(se); - assertEquals("java.lang.Exception: Test-DLSE", ioe2.getMessage()); - assertTrue(se == ioe2.getCause()); - ExecutionException ee = new ExecutionException(ioe); - assertTrue(ioe == toIOException(ee)); - CompletionException ce = new CompletionException(ioe); - assertTrue(ioe == toIOException(ce)); - } - -} diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestVarInt.java b/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestVarInt.java deleted file mode 100644 index 0e6d1b6138d..00000000000 --- a/stream/common/src/test/java/org/apache/bookkeeper/common/util/TestVarInt.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.common.util; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -import java.io.IOException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -/** - * Test Case for {@link VarInt}. - */ -public class TestVarInt { - @Rule - public final ExpectedException thrown = ExpectedException.none(); - - // Long values to check for boundary cases. - private static final long[] LONG_VALUES = { - 0, - 1, - 127, - 128, - 16383, - 16384, - 2097151, - 2097152, - 268435455, - 268435456, - 34359738367L, - 34359738368L, - 9223372036854775807L, - -9223372036854775808L, - -1, - }; - - // VarInt encoding of the above VALUES. - private static final byte[][] LONG_ENCODED = { - // 0 - {0x00}, - // 1 - {0x01}, - // 127 - {0x7f}, - // 128 - {(byte) 0x80, 0x01}, - // 16383 - {(byte) 0xff, 0x7f}, - // 16834 - {(byte) 0x80, (byte) 0x80, 0x01}, - // 2097151 - {(byte) 0xff, (byte) 0xff, 0x7f}, - // 2097152 - {(byte) 0x80, (byte) 0x80, (byte) 0x80, 0x01}, - // 268435455 - {(byte) 0xff, (byte) 0xff, (byte) 0xff, 0x7f}, - // 268435456 - {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, 0x01}, - // 34359738367 - {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x7f}, - // 34359738368 - {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, - 0x01}, - // 9223372036854775807 - {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f}, - // -9223372036854775808L - {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, - (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, 0x01}, - // -1 - {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x01} - }; - - // Integer values to check for boundary cases. - private static final int[] INT_VALUES = { - 0, - 1, - 127, - 128, - 16383, - 16384, - 2097151, - 2097152, - 268435455, - 268435456, - 2147483647, - -2147483648, - -1, - }; - - // VarInt encoding of the above VALUES. - private static final byte[][] INT_ENCODED = { - // 0 - {(byte) 0x00}, - // 1 - {(byte) 0x01}, - // 127 - {(byte) 0x7f}, - // 128 - {(byte) 0x80, (byte) 0x01}, - // 16383 - {(byte) 0xff, (byte) 0x7f}, - // 16834 - {(byte) 0x80, (byte) 0x80, (byte) 0x01}, - // 2097151 - {(byte) 0xff, (byte) 0xff, (byte) 0x7f}, - // 2097152 - {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01}, - // 268435455 - {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f}, - // 268435456 - {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01}, - // 2147483647 - {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07}, - // -2147483648 - {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x08}, - // -1 - {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f} - }; - - private static byte[] encodeInt(int v) throws IOException { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - VarInt.encode(v, stream); - return stream.toByteArray(); - } - - private static byte[] encodeLong(long v) throws IOException { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - VarInt.encode(v, stream); - return stream.toByteArray(); - } - - private static int decodeInt(byte[] encoded) throws IOException { - ByteArrayInputStream stream = new ByteArrayInputStream(encoded); - return VarInt.decodeInt(stream); - } - - private static long decodeLong(byte[] encoded) throws IOException { - ByteArrayInputStream stream = new ByteArrayInputStream(encoded); - return VarInt.decodeLong(stream); - } - - @Test - public void decodeValues() throws IOException { - assertEquals(LONG_VALUES.length, LONG_ENCODED.length); - for (int i = 0; i < LONG_ENCODED.length; ++i) { - ByteArrayInputStream stream = new ByteArrayInputStream(LONG_ENCODED[i]); - long parsed = VarInt.decodeLong(stream); - assertEquals(LONG_VALUES[i], parsed); - assertEquals(-1, stream.read()); - } - - assertEquals(INT_VALUES.length, INT_ENCODED.length); - for (int i = 0; i < INT_ENCODED.length; ++i) { - ByteArrayInputStream stream = new ByteArrayInputStream(INT_ENCODED[i]); - int parsed = VarInt.decodeInt(stream); - assertEquals(INT_VALUES[i], parsed); - assertEquals(-1, stream.read()); - } - } - - @Test - public void encodeValuesAndGetLength() throws IOException { - assertEquals(LONG_VALUES.length, LONG_ENCODED.length); - for (int i = 0; i < LONG_VALUES.length; ++i) { - byte[] encoded = encodeLong(LONG_VALUES[i]); - assertThat(encoded, equalTo(LONG_ENCODED[i])); - assertEquals(LONG_ENCODED[i].length, VarInt.getLength(LONG_VALUES[i])); - } - - assertEquals(INT_VALUES.length, INT_ENCODED.length); - for (int i = 0; i < INT_VALUES.length; ++i) { - byte[] encoded = encodeInt(INT_VALUES[i]); - assertThat(encoded, equalTo(INT_ENCODED[i])); - assertEquals(INT_ENCODED[i].length, VarInt.getLength(INT_VALUES[i])); - } - } - - @Test - public void decodeThrowsExceptionForOverflow() throws IOException { - final byte[] tooLargeNumber = - {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x02}; - - thrown.expect(IOException.class); - decodeLong(tooLargeNumber); - } - - @Test - public void decodeThrowsExceptionForIntOverflow() throws IOException { - byte[] encoded = encodeLong(1L << 32); - - thrown.expect(IOException.class); - decodeInt(encoded); - } - - @Test - public void decodeThrowsExceptionForIntUnderflow() throws IOException { - byte[] encoded = encodeLong(-1); - - thrown.expect(IOException.class); - decodeInt(encoded); - } - - @Test - public void decodeThrowsExceptionForNonterminated() throws IOException { - final byte[] nonTerminatedNumber = - {(byte) 0xff, (byte) 0xff}; - - thrown.expect(IOException.class); - decodeLong(nonTerminatedNumber); - } - - @Test - public void decodeParsesEncodedValues() throws IOException { - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - for (int i = 10; i < Integer.MAX_VALUE; i = (int) (i * 1.1)) { - VarInt.encode(i, outStream); - VarInt.encode(-i, outStream); - } - for (long i = 10; i < Long.MAX_VALUE; i = (long) (i * 1.1)) { - VarInt.encode(i, outStream); - VarInt.encode(-i, outStream); - } - - ByteArrayInputStream inStream = - new ByteArrayInputStream(outStream.toByteArray()); - for (int i = 10; i < Integer.MAX_VALUE; i = (int) (i * 1.1)) { - assertEquals(i, VarInt.decodeInt(inStream)); - assertEquals(-i, VarInt.decodeInt(inStream)); - } - for (long i = 10; i < Long.MAX_VALUE; i = (long) (i * 1.1)) { - assertEquals(i, VarInt.decodeLong(inStream)); - assertEquals(-i, VarInt.decodeLong(inStream)); - } - } - - @Test - public void endOfFileThrowsException() throws Exception { - ByteArrayInputStream inStream = - new ByteArrayInputStream(new byte[0]); - thrown.expect(EOFException.class); - VarInt.decodeInt(inStream); - } - - @Test - public void unterminatedThrowsException() throws Exception { - byte[] e = encodeLong(Long.MAX_VALUE); - byte[] s = new byte[1]; - s[0] = e[0]; - ByteArrayInputStream inStream = new ByteArrayInputStream(s); - thrown.expect(IOException.class); - VarInt.decodeInt(inStream); - } -} diff --git a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/PropertiesWriter.java b/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/PropertiesWriter.java deleted file mode 100644 index 0de35e5077a..00000000000 --- a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/PropertiesWriter.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.common.config; - -import java.io.File; -import java.io.FileOutputStream; -import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer to write properties to files. - */ -public class PropertiesWriter { - static final Logger LOG = LoggerFactory.getLogger(PropertiesWriter.class); - - final FileOutputStream outputStream; - final File configFile; - final Properties properties; - - public PropertiesWriter() throws Exception { - this(null); - } - - public PropertiesWriter(File configFile) throws Exception { - if (null == configFile) { - this.configFile = File.createTempFile("temp", ".conf"); - } else { - this.configFile = configFile; - } - this.configFile.deleteOnExit(); - this.properties = new Properties(); - this.outputStream = new FileOutputStream(this.configFile); - } - - public void setProperty(String key, String value) { - properties.setProperty(key, value); - } - - public void removeProperty(String key) { - properties.remove(key); - } - - public void save() throws Exception { - FileOutputStream outputStream = new FileOutputStream(configFile); - properties.store(outputStream, null); - configFile.setLastModified(configFile.lastModified() + 1000); - if (LOG.isDebugEnabled()) { - LOG.debug("save modified={}", configFile.lastModified()); - } - } - - public File getFile() { - return configFile; - } -} diff --git a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConcurrentBaseConfiguration.java b/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConcurrentBaseConfiguration.java deleted file mode 100644 index a54faa04162..00000000000 --- a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConcurrentBaseConfiguration.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.common.config; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -/** - * Unit test of {@link ConcurrentBaseConfiguration}. - */ -public class TestConcurrentBaseConfiguration { - - @Test(timeout = 20000) - public void testBasicOperations() throws Exception { - ConcurrentBaseConfiguration conf = new ConcurrentBaseConfiguration(); - conf.setProperty("prop1", "1"); - assertEquals(1, conf.getInt("prop1")); - conf.setProperty("prop1", "2"); - assertEquals(2, conf.getInt("prop1")); - conf.clearProperty("prop1"); - assertEquals(null, conf.getInteger("prop1", null)); - conf.setProperty("prop1", "1"); - conf.setProperty("prop2", "2"); - assertEquals(1, conf.getInt("prop1")); - assertEquals(2, conf.getInt("prop2")); - conf.clearProperty("prop1"); - assertEquals(null, conf.getInteger("prop1", null)); - assertEquals(2, conf.getInt("prop2")); - } - -} diff --git a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConfigurationSubscription.java b/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConfigurationSubscription.java deleted file mode 100644 index a474f894186..00000000000 --- a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/common/config/TestConfigurationSubscription.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.common.config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.event.ConfigurationEvent; -import org.apache.commons.configuration.event.ConfigurationListener; -import org.jmock.lib.concurrent.DeterministicScheduler; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Notes: - * 1. lastModified granularity is platform dependent, generally 1 sec, so we can't wait 1ms for things to - * get picked up. - */ -public class TestConfigurationSubscription { - static final Logger LOG = LoggerFactory.getLogger(TestConfigurationSubscription.class); - - /** - * Give FileChangedReloadingStrategy some time to start reloading. - * - *

Make sure now!=lastChecked - * {@link org.apache.commons.configuration.reloading.FileChangedReloadingStrategy#reloadingRequired()} - */ - private void ensureConfigReloaded() throws InterruptedException { - // sleep 1 ms so that System.currentTimeMillis() != - // lastChecked (the time we construct FileChangedReloadingStrategy - Thread.sleep(1); - } - - @Test(timeout = 60000) - public void testReloadConfiguration() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - FileConfigurationBuilder builder = new PropertiesConfigurationBuilder(writer.getFile().toURI().toURL()); - ConcurrentConstConfiguration conf = new ConcurrentConstConfiguration(new CompositeConfiguration()); - DeterministicScheduler executorService = new DeterministicScheduler(); - List fileConfigBuilders = Lists.newArrayList(builder); - ConfigurationSubscription confSub = - new ConfigurationSubscription(conf, fileConfigBuilders, executorService, 100, TimeUnit.MILLISECONDS); - final AtomicReference confHolder = new AtomicReference<>(); - confSub.registerListener(new org.apache.distributedlog.common.config.ConfigurationListener() { - @Override - public void onReload(ConcurrentBaseConfiguration conf) { - confHolder.set(conf); - } - }); - assertEquals(null, conf.getProperty("prop1")); - - // add - writer.setProperty("prop1", "1"); - writer.save(); - // ensure the file change reloading event can be triggered - ensureConfigReloaded(); - // reload the config - confSub.reload(); - assertNotNull(confHolder.get()); - assertTrue(conf == confHolder.get()); - assertEquals("1", conf.getProperty("prop1")); - } - - @Test(timeout = 60000) - public void testAddReloadBasicsConfig() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - DeterministicScheduler mockScheduler = new DeterministicScheduler(); - FileConfigurationBuilder builder = new PropertiesConfigurationBuilder(writer.getFile().toURI().toURL()); - ConcurrentConstConfiguration conf = new ConcurrentConstConfiguration(new CompositeConfiguration()); - List fileConfigBuilders = Lists.newArrayList(builder); - ConfigurationSubscription confSub = - new ConfigurationSubscription(conf, fileConfigBuilders, mockScheduler, 100, TimeUnit.MILLISECONDS); - assertEquals(null, conf.getProperty("prop1")); - - // add - writer.setProperty("prop1", "1"); - writer.save(); - // ensure the file change reloading event can be triggered - ensureConfigReloaded(); - mockScheduler.tick(100, TimeUnit.MILLISECONDS); - assertEquals("1", conf.getProperty("prop1")); - - } - - @Test(timeout = 60000) - public void testInitialConfigLoad() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - writer.setProperty("prop1", "1"); - writer.setProperty("prop2", "abc"); - writer.setProperty("prop3", "123.0"); - writer.setProperty("prop4", "11132"); - writer.setProperty("prop5", "true"); - writer.save(); - - ScheduledExecutorService mockScheduler = new DeterministicScheduler(); - FileConfigurationBuilder builder = new PropertiesConfigurationBuilder(writer.getFile().toURI().toURL()); - ConcurrentConstConfiguration conf = new ConcurrentConstConfiguration(new CompositeConfiguration()); - List fileConfigBuilders = Lists.newArrayList(builder); - ConfigurationSubscription confSub = - new ConfigurationSubscription(conf, fileConfigBuilders, mockScheduler, 100, TimeUnit.MILLISECONDS); - assertEquals(1, conf.getInt("prop1")); - assertEquals("abc", conf.getString("prop2")); - assertEquals(123.0, conf.getFloat("prop3"), 0); - assertEquals(11132, conf.getInt("prop4")); - assertEquals(true, conf.getBoolean("prop5")); - } - - @Test(timeout = 60000) - public void testExceptionInConfigLoad() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - writer.setProperty("prop1", "1"); - writer.save(); - - DeterministicScheduler mockScheduler = new DeterministicScheduler(); - FileConfigurationBuilder builder = new PropertiesConfigurationBuilder(writer.getFile().toURI().toURL()); - ConcurrentConstConfiguration conf = new ConcurrentConstConfiguration(new CompositeConfiguration()); - List fileConfigBuilders = Lists.newArrayList(builder); - ConfigurationSubscription confSub = - new ConfigurationSubscription(conf, fileConfigBuilders, mockScheduler, 100, TimeUnit.MILLISECONDS); - - final AtomicInteger count = new AtomicInteger(1); - conf.addConfigurationListener(new ConfigurationListener() { - @Override - public void configurationChanged(ConfigurationEvent event) { - LOG.info("config changed {}", event); - // Throw after so we actually see the update anyway. - if (!event.isBeforeUpdate()) { - count.getAndIncrement(); - throw new RuntimeException("config listener threw and exception"); - } - } - }); - - int i = 0; - int initial = 0; - while (count.get() == initial) { - writer.setProperty("prop1", Integer.toString(i++)); - writer.save(); - mockScheduler.tick(100, TimeUnit.MILLISECONDS); - } - - initial = count.get(); - while (count.get() == initial) { - writer.setProperty("prop1", Integer.toString(i++)); - writer.save(); - mockScheduler.tick(100, TimeUnit.MILLISECONDS); - } - } -} diff --git a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/io/TestCompressionCodec.java b/stream/distributedlog/common/src/test/java/org/apache/distributedlog/io/TestCompressionCodec.java deleted file mode 100644 index 715eee6415a..00000000000 --- a/stream/distributedlog/common/src/test/java/org/apache/distributedlog/io/TestCompressionCodec.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.io; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCountUtil; -import java.nio.ByteBuffer; -import org.junit.Test; - -/** - * Test Case for {@link CompressionCodec}. - */ -public class TestCompressionCodec { - - @Test(timeout = 10000) - public void testUnknownCompressionCodec() throws Exception { - assertEquals( - CompressionCodec.Type.UNKNOWN, - CompressionUtils.stringToType("unknown")); - } - - @Test(timeout = 10000) - public void testIdentityCompressionCodec() throws Exception { - testCompressionCodec(CompressionUtils.getCompressionCodec(CompressionCodec.Type.NONE)); - } - - @Test(timeout = 10000) - public void testLZ4CompressionCodec() throws Exception { - testCompressionCodec(CompressionUtils.getCompressionCodec(CompressionCodec.Type.LZ4)); - } - - @Test(timeout = 10000) - public void testIdentityCompressionCodec2() throws Exception { - testCompressionCodec2(CompressionUtils.getCompressionCodec(CompressionCodec.Type.NONE)); - } - - @Test(timeout = 10000) - public void testLZ4CompressionCodec2() throws Exception { - testCompressionCodec2(CompressionUtils.getCompressionCodec(CompressionCodec.Type.LZ4)); - } - - private void testCompressionCodec(CompressionCodec codec) throws Exception { - byte[] data = "identity-compression-codec".getBytes(UTF_8); - ByteBuf buf = Unpooled.wrappedBuffer(data); - ByteBuf compressedBuf = codec.compress(buf, 0); - ByteBuf decompressedBuf = codec.decompress(compressedBuf, data.length); - assertEquals("The length of decompressed buf should be same as the original buffer", - data.length, decompressedBuf.readableBytes()); - byte[] decompressedData = new byte[data.length]; - decompressedBuf.readBytes(decompressedData); - assertArrayEquals("The decompressed bytes should be same as the original bytes", - data, decompressedData); - ReferenceCountUtil.release(buf); - ReferenceCountUtil.release(compressedBuf); - ReferenceCountUtil.release(decompressedBuf); - } - - private void testCompressionCodec2(CompressionCodec codec) throws Exception { - ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(32, 4 * 1024 * 1024); - for (int i = 0; i < 100; i++) { - ByteBuffer record = ByteBuffer.wrap(("record-" + i).getBytes(UTF_8)); - buffer.writeInt(record.remaining()); - buffer.writeBytes(record); - } - byte[] uncompressedData = new byte[buffer.readableBytes()]; - buffer.slice().readBytes(uncompressedData); - - ByteBuf compressedBuf = codec.compress(buffer, 0); - byte[] compressedData = new byte[compressedBuf.readableBytes()]; - compressedBuf.slice().readBytes(compressedData); - - ByteBuf decompressedBuf = codec.decompress(compressedBuf, uncompressedData.length); - byte[] decompressedData = new byte[decompressedBuf.readableBytes()]; - decompressedBuf.slice().readBytes(decompressedData); - - ReferenceCountUtil.release(buffer); - ReferenceCountUtil.release(compressedBuf); - ReferenceCountUtil.release(decompressedBuf); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/DLMTestUtil.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/DLMTestUtil.java deleted file mode 100644 index ec27b19bb0c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/DLMTestUtil.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.feature.SettableFeatureProvider; -import org.apache.bookkeeper.versioning.Version; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.common.util.PermitLimiter; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.impl.logsegment.BKLogSegmentEntryWriter; -import org.apache.distributedlog.logsegment.LogSegmentEntryStore; -import org.apache.distributedlog.namespace.NamespaceDriver; -import org.apache.distributedlog.util.ConfUtils; -import org.apache.distributedlog.util.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class for setting up bookkeeper ensembles - * and bringing individual bookies up and down. - */ -public class DLMTestUtil { - protected static final Logger LOG = LoggerFactory.getLogger(DLMTestUtil.class); - private static final byte[] payloadStatic = repeatString("abc", 512).getBytes(); - - static String repeatString(String s, int n) { - StringBuilder ret = new StringBuilder(s); - for (int i = 1; i < n; i++) { - ret.append(s); - } - return ret.toString(); - } - - public static Map readLogSegments(ZooKeeperClient zkc, String ledgerPath) - throws Exception { - List children = zkc.get().getChildren(ledgerPath, false); - LOG.info("Children under {} : {}", ledgerPath, children); - Map segments = - new HashMap(children.size()); - for (String child : children) { - LogSegmentMetadata segment = - Utils.ioResult(LogSegmentMetadata.read(zkc, ledgerPath + "/" + child)); - LOG.info("Read segment {} : {}", child, segment); - segments.put(segment.getLogSegmentSequenceNumber(), segment); - } - return segments; - } - - public static URI createDLMURI(int port, String path) throws Exception { - return LocalDLMEmulator.createDLMURI("127.0.0.1:" + port, path); - } - - public static DistributedLogManager createNewDLM(String name, - DistributedLogConfiguration conf, - URI uri) throws Exception { - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf).uri(uri).build(); - return namespace.openLog(name); - } - - @SuppressWarnings("deprecation") - static org.apache.distributedlog.api.MetadataAccessor createNewMetadataAccessor( - DistributedLogConfiguration conf, - String name, - URI uri) throws Exception { - // TODO: Metadata Accessor seems to be a legacy object which only used by kestrel - // (we might consider deprecating this) - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf).uri(uri).build(); - return namespace.getNamespaceDriver().getMetadataAccessor(name); - } - - public static void fenceStream(DistributedLogConfiguration conf, URI uri, String name) throws Exception { - DistributedLogManager dlm = createNewDLM(name, conf, uri); - try { - List logSegmentList = dlm.getLogSegments(); - LogSegmentMetadata lastSegment = logSegmentList.get(logSegmentList.size() - 1); - LogSegmentEntryStore entryStore = - dlm.getNamespaceDriver().getLogSegmentEntryStore(NamespaceDriver.Role.READER); - Utils.close(Utils.ioResult(entryStore.openRandomAccessReader(lastSegment, true))); - } finally { - dlm.close(); - } - } - - static long getNumberofLogRecords(DistributedLogManager bkdlm, long startTxId) throws IOException { - long numLogRecs = 0; - LogReader reader = bkdlm.getInputStream(startTxId); - LogRecord record = reader.readNext(false); - while (null != record) { - numLogRecs++; - verifyLogRecord(record); - record = reader.readNext(false); - } - reader.close(); - return numLogRecs; - } - - public static LogRecord getLogRecordInstance(long txId) { - return new LogRecord(txId, generatePayload(txId)); - } - - public static LogRecord getLogRecordInstance(long txId, int size) { - ByteBuffer buf = ByteBuffer.allocate(size); - return new LogRecord(txId, buf.array()); - } - - public static void verifyLogRecord(LogRecord record) { - assertEquals(generatePayload(record.getTransactionId()).length, record.getPayload().length); - assertArrayEquals(generatePayload(record.getTransactionId()), record.getPayload()); - assertTrue(!record.isControl()); - verifyPayload(record.getTransactionId(), record.getPayload()); - } - - static byte[] generatePayload(long txId) { - return String.format("%d;%d", txId, txId).getBytes(); - } - - static void verifyPayload(long txId, byte[] payload) { - String[] txIds = new String(payload).split(";"); - assertEquals(Long.valueOf(txIds[0]), Long.valueOf(txIds[0])); - } - - static LogRecord getLargeLogRecordInstance(long txId, boolean control) { - LogRecord record = new LogRecord(txId, payloadStatic); - if (control) { - record.setControl(); - } - return record; - } - - static LogRecord getLargeLogRecordInstance(long txId) { - return new LogRecord(txId, payloadStatic); - } - - static List getLargeLogRecordInstanceList(long firstTxId, int count) { - List logrecs = new ArrayList(count); - for (long i = 0; i < count; i++) { - logrecs.add(getLargeLogRecordInstance(firstTxId + i)); - } - return logrecs; - } - - static List getLogRecordInstanceList(long firstTxId, int count, int size) { - List logrecs = new ArrayList(count); - for (long i = 0; i < count; i++) { - logrecs.add(getLogRecordInstance(firstTxId + i, size)); - } - return logrecs; - } - - static void verifyLargeLogRecord(LogRecord record) { - verifyLargeLogRecord(record.getPayload()); - } - - static void verifyLargeLogRecord(byte[] payload) { - assertArrayEquals(payloadStatic, payload); - } - - static LogRecord getEmptyLogRecordInstance(long txId) { - return new LogRecord(txId, new byte[0]); - } - - static void verifyEmptyLogRecord(LogRecord record) { - assertEquals(record.getPayload().length, 0); - } - - public static LogRecordWithDLSN getLogRecordWithDLSNInstance(DLSN dlsn, long txId) { - return getLogRecordWithDLSNInstance(dlsn, txId, false); - } - - public static LogRecordWithDLSN getLogRecordWithDLSNInstance(DLSN dlsn, long txId, boolean isControlRecord) { - LogRecordWithDLSN record = new LogRecordWithDLSN(dlsn, txId, generatePayload(txId), 1L); - record.setPositionWithinLogSegment((int) txId + 1); - if (isControlRecord) { - record.setControl(); - } - return record; - } - - public static String inprogressZNodeName(long logSegmentSeqNo) { - return String.format("%s_%018d", DistributedLogConstants.INPROGRESS_LOGSEGMENT_PREFIX, logSegmentSeqNo); - } - - public static String completedLedgerZNodeNameWithVersion(long ledgerId, - long firstTxId, long lastTxId, long logSegmentSeqNo) { - return String.format("%s_%018d_%018d_%018d_v%dl%d_%04d", DistributedLogConstants.COMPLETED_LOGSEGMENT_PREFIX, - firstTxId, lastTxId, logSegmentSeqNo, DistributedLogConstants.LOGSEGMENT_NAME_VERSION, ledgerId, - DistributedLogConstants.LOCAL_REGION_ID); - } - - public static String completedLedgerZNodeNameWithTxID(long firstTxId, long lastTxId) { - return String.format("%s_%018d_%018d", - DistributedLogConstants.COMPLETED_LOGSEGMENT_PREFIX, firstTxId, lastTxId); - } - - public static String completedLedgerZNodeNameWithLogSegmentSequenceNumber(long logSegmentSeqNo) { - return String.format("%s_%018d", DistributedLogConstants.COMPLETED_LOGSEGMENT_PREFIX, logSegmentSeqNo); - } - - public static LogSegmentMetadata inprogressLogSegment(String ledgerPath, - long ledgerId, - long firstTxId, - long logSegmentSeqNo) { - return inprogressLogSegment(ledgerPath, ledgerId, firstTxId, logSegmentSeqNo, - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - } - - public static LogSegmentMetadata inprogressLogSegment(String ledgerPath, - long ledgerId, - long firstTxId, - long logSegmentSeqNo, - int version) { - return new LogSegmentMetadata.LogSegmentMetadataBuilder( - ledgerPath + "/" + inprogressZNodeName(logSegmentSeqNo), - version, - ledgerId, - firstTxId) - .setLogSegmentSequenceNo(logSegmentSeqNo) - .build(); - } - - public static LogSegmentMetadata completedLogSegment(String ledgerPath, - long ledgerId, - long firstTxId, - long lastTxId, - int recordCount, - long logSegmentSeqNo, - long lastEntryId, - long lastSlotId) { - return completedLogSegment(ledgerPath, ledgerId, firstTxId, lastTxId, - recordCount, logSegmentSeqNo, lastEntryId, lastSlotId, - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - } - - public static LogSegmentMetadata completedLogSegment(String ledgerPath, - long ledgerId, - long firstTxId, - long lastTxId, - int recordCount, - long logSegmentSeqNo, - long lastEntryId, - long lastSlotId, - int version) { - LogSegmentMetadata metadata = - new LogSegmentMetadata.LogSegmentMetadataBuilder( - ledgerPath + "/" + inprogressZNodeName(logSegmentSeqNo), - version, - ledgerId, - firstTxId) - .setInprogress(false) - .setLogSegmentSequenceNo(logSegmentSeqNo) - .build(); - return metadata.completeLogSegment(ledgerPath + "/" - + completedLedgerZNodeNameWithLogSegmentSequenceNumber(logSegmentSeqNo), - lastTxId, recordCount, lastEntryId, lastSlotId, firstTxId); - } - - public static void generateCompletedLogSegments(DistributedLogManager manager, DistributedLogConfiguration conf, - long numCompletedSegments, long segmentSize) throws Exception { - BKDistributedLogManager dlm = (BKDistributedLogManager) manager; - long txid = 1L; - for (long i = 0; i < numCompletedSegments; i++) { - BKSyncLogWriter writer = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= segmentSize; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - writer.closeAndComplete(); - } - } - - public static long generateLogSegmentNonPartitioned(DistributedLogManager dlm, - int controlEntries, int userEntries, long startTxid) throws Exception { - return generateLogSegmentNonPartitioned(dlm, controlEntries, userEntries, startTxid, 1L); - } - - public static long generateLogSegmentNonPartitioned(DistributedLogManager dlm, int controlEntries, - int userEntries, long startTxid, long txidStep) throws Exception { - AsyncLogWriter out = dlm.startAsyncLogSegmentNonPartitioned(); - long txid = startTxid; - for (int i = 0; i < controlEntries; ++i) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid); - record.setControl(); - Utils.ioResult(out.write(record)); - txid += txidStep; - } - for (int i = 0; i < userEntries; ++i) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid); - Utils.ioResult(out.write(record)); - txid += txidStep; - } - Utils.close(out); - return txid - startTxid; - } - - public static ZooKeeperClient getZooKeeperClient(BKDistributedLogManager dlm) { - return ((BKNamespaceDriver) dlm.getNamespaceDriver()).getWriterZKC(); - } - - public static BookKeeperClient getBookKeeperClient(BKDistributedLogManager dlm) { - return ((BKNamespaceDriver) dlm.getNamespaceDriver()).getReaderBKC(); - } - - public static void injectLogSegmentWithGivenLogSegmentSeqNo(DistributedLogManager manager, - DistributedLogConfiguration conf, long logSegmentSeqNo, long startTxID, - boolean writeEntries, long segmentSize, boolean completeLogSegment) - throws Exception { - BKDistributedLogManager dlm = (BKDistributedLogManager) manager; - BKLogWriteHandler writeHandler = dlm.createWriteHandler(false); - Utils.ioResult(writeHandler.lockHandler()); - // Start a log segment with a given ledger seq number. - BookKeeperClient bkc = getBookKeeperClient(dlm); - LedgerHandle lh = bkc.get().createLedger(conf.getEnsembleSize(), conf.getWriteQuorumSize(), - conf.getAckQuorumSize(), BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes()); - String inprogressZnodeName = writeHandler.inprogressZNodeName(lh.getId(), startTxID, logSegmentSeqNo); - String znodePath = writeHandler.inprogressZNode(lh.getId(), startTxID, logSegmentSeqNo); - int logSegmentMetadataVersion = conf.getDLLedgerMetadataLayoutVersion(); - LogSegmentMetadata l = - new LogSegmentMetadata.LogSegmentMetadataBuilder(znodePath, - logSegmentMetadataVersion, lh.getId(), startTxID) - .setLogSegmentSequenceNo(logSegmentSeqNo) - .setEnvelopeEntries(LogSegmentMetadata.supportsEnvelopedEntries(logSegmentMetadataVersion)) - .build(); - l.write(getZooKeeperClient(dlm)); - writeHandler.maxTxId.update(Version.ANY, startTxID); - writeHandler.addLogSegmentToCache(inprogressZnodeName, l); - BKLogSegmentWriter writer = new BKLogSegmentWriter( - writeHandler.getFullyQualifiedName(), - inprogressZnodeName, - conf, - conf.getDLLedgerMetadataLayoutVersion(), - new BKLogSegmentEntryWriter(lh), - writeHandler.lock, - startTxID, - logSegmentSeqNo, - writeHandler.scheduler, - writeHandler.statsLogger, - writeHandler.statsLogger, - writeHandler.alertStatsLogger, - PermitLimiter.NULL_PERMIT_LIMITER, - new SettableFeatureProvider("", 0), - ConfUtils.getConstDynConf(conf)); - if (writeEntries) { - long txid = startTxID; - for (long j = 1; j <= segmentSize; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - Utils.ioResult(writer.flushAndCommit()); - } - if (completeLogSegment) { - Utils.ioResult(writeHandler.completeAndCloseLogSegment(writer)); - } - Utils.ioResult(writeHandler.unlockHandler()); - } - - public static void injectLogSegmentWithLastDLSN(DistributedLogManager manager, DistributedLogConfiguration conf, - long logSegmentSeqNo, long startTxID, long segmentSize, - boolean recordWrongLastDLSN) throws Exception { - BKDistributedLogManager dlm = (BKDistributedLogManager) manager; - BKLogWriteHandler writeHandler = dlm.createWriteHandler(false); - Utils.ioResult(writeHandler.lockHandler()); - // Start a log segment with a given ledger seq number. - BookKeeperClient bkc = getBookKeeperClient(dlm); - LedgerHandle lh = bkc.get().createLedger(conf.getEnsembleSize(), conf.getWriteQuorumSize(), - conf.getAckQuorumSize(), BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes()); - String inprogressZnodeName = writeHandler.inprogressZNodeName(lh.getId(), startTxID, logSegmentSeqNo); - String znodePath = writeHandler.inprogressZNode(lh.getId(), startTxID, logSegmentSeqNo); - LogSegmentMetadata l = - new LogSegmentMetadata.LogSegmentMetadataBuilder(znodePath, - conf.getDLLedgerMetadataLayoutVersion(), lh.getId(), startTxID) - .setLogSegmentSequenceNo(logSegmentSeqNo) - .setInprogress(false) - .build(); - l.write(getZooKeeperClient(dlm)); - writeHandler.maxTxId.update(Version.ANY, startTxID); - writeHandler.addLogSegmentToCache(inprogressZnodeName, l); - BKLogSegmentWriter writer = new BKLogSegmentWriter( - writeHandler.getFullyQualifiedName(), - inprogressZnodeName, - conf, - conf.getDLLedgerMetadataLayoutVersion(), - new BKLogSegmentEntryWriter(lh), - writeHandler.lock, - startTxID, - logSegmentSeqNo, - writeHandler.scheduler, - writeHandler.statsLogger, - writeHandler.statsLogger, - writeHandler.alertStatsLogger, - PermitLimiter.NULL_PERMIT_LIMITER, - new SettableFeatureProvider("", 0), - ConfUtils.getConstDynConf(conf)); - long txid = startTxID; - DLSN wrongDLSN = null; - for (long j = 1; j <= segmentSize; j++) { - DLSN dlsn = Utils.ioResult(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(txid++))); - if (j == (segmentSize - 1)) { - wrongDLSN = dlsn; - } - } - assertNotNull(wrongDLSN); - if (recordWrongLastDLSN) { - Utils.ioResult(writer.asyncClose()); - writeHandler.completeAndCloseLogSegment( - writeHandler.inprogressZNodeName(writer.getLogSegmentId(), - writer.getStartTxId(), writer.getLogSegmentSequenceNumber()), - writer.getLogSegmentSequenceNumber(), - writer.getLogSegmentId(), - writer.getStartTxId(), - startTxID + segmentSize - 2, - writer.getPositionWithinLogSegment() - 1, - wrongDLSN.getEntryId(), - wrongDLSN.getSlotId()); - } else { - Utils.ioResult(writeHandler.completeAndCloseLogSegment(writer)); - } - Utils.ioResult(writeHandler.unlockHandler()); - } - - public static void updateSegmentMetadata(ZooKeeperClient zkc, LogSegmentMetadata segment) throws Exception { - byte[] finalisedData = segment.getFinalisedData().getBytes(UTF_8); - zkc.get().setData(segment.getZkPath(), finalisedData, -1); - } - - public static ServerConfiguration loadTestBkConf() { - ServerConfiguration conf = new ServerConfiguration(); - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - URL confUrl = classLoader.getResource("bk_server.conf"); - try { - if (null != confUrl) { - conf.loadConf(confUrl); - LOG.info("loaded bk_server.conf from resources"); - } - } catch (org.apache.commons.configuration.ConfigurationException ex) { - LOG.warn("loading conf failed", ex); - } - conf.setAllowLoopback(true); - return conf; - } - - public static void validateFutureFailed(CompletableFuture future, Class exClass) { - try { - Utils.ioResult(future); - } catch (Exception ex) { - LOG.info("Expected: {} Actual: {}", exClass.getName(), ex.getClass().getName()); - assertTrue("exceptions types equal", exClass.isInstance(ex)); - } - } - - public static T validateFutureSucceededAndGetResult(CompletableFuture future) throws Exception { - try { - return Utils.ioResult(future, 10, TimeUnit.SECONDS); - } catch (Exception ex) { - fail("unexpected exception " + ex.getClass().getName()); - throw ex; - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/NonBlockingReadsTestUtil.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/NonBlockingReadsTestUtil.java deleted file mode 100644 index 71004527971..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/NonBlockingReadsTestUtil.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.exceptions.LogEmptyException; -import org.apache.distributedlog.exceptions.LogNotFoundException; -import org.apache.distributedlog.exceptions.LogReadException; -import org.apache.distributedlog.util.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - - -/** - * Utils for non blocking reads tests. - */ -class NonBlockingReadsTestUtil { - - static final Logger LOG = LoggerFactory.getLogger(NonBlockingReadsTestUtil.class); - - static final long DEFAULT_SEGMENT_SIZE = 1000; - - static void readNonBlocking(DistributedLogManager dlm, boolean forceStall) throws Exception { - readNonBlocking(dlm, forceStall, DEFAULT_SEGMENT_SIZE, false); - } - - static void readNonBlocking(DistributedLogManager dlm, - boolean forceStall, - long segmentSize, - boolean waitForIdle) throws Exception { - BKSyncLogReader reader = null; - try { - reader = (BKSyncLogReader) dlm.getInputStream(1); - } catch (LogNotFoundException lnfe) { - } - while (null == reader) { - TimeUnit.MILLISECONDS.sleep(20); - try { - reader = (BKSyncLogReader) dlm.getInputStream(1); - } catch (LogNotFoundException lnfe) { - } catch (LogEmptyException lee) { - } catch (IOException ioe) { - LOG.error("Failed to open reader reading from {}", dlm.getStreamName()); - throw ioe; - } - } - try { - LOG.info("Created reader reading from {}", dlm.getStreamName()); - if (forceStall) { - reader.getReadHandler().disableReadAheadLogSegmentsNotification(); - } - - long numTrans = 0; - long lastTxId = -1; - - boolean exceptionEncountered = false; - try { - while (true) { - LogRecordWithDLSN record = reader.readNext(true); - if (null != record) { - DLMTestUtil.verifyLogRecord(record); - assertTrue(lastTxId < record.getTransactionId()); - assertEquals(record.getTransactionId() - 1, record.getSequenceId()); - lastTxId = record.getTransactionId(); - numTrans++; - continue; - } - - if (numTrans >= (3 * segmentSize)) { - if (waitForIdle) { - while (true) { - reader.readNext(true); - TimeUnit.MILLISECONDS.sleep(10); - } - } - break; - } - - TimeUnit.MILLISECONDS.sleep(2); - } - } catch (LogReadException readexc) { - exceptionEncountered = true; - } catch (LogNotFoundException exc) { - exceptionEncountered = true; - } - assertFalse(exceptionEncountered); - } finally { - reader.close(); - } - } - - static void writeRecordsForNonBlockingReads(DistributedLogConfiguration conf, - DistributedLogManager dlm, - boolean recover) - throws Exception { - writeRecordsForNonBlockingReads(conf, dlm, recover, DEFAULT_SEGMENT_SIZE); - } - - static void writeRecordsForNonBlockingReads(DistributedLogConfiguration conf, - DistributedLogManager dlm, - boolean recover, - long segmentSize) - throws Exception { - long txId = 1; - for (long i = 0; i < 3; i++) { - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j < segmentSize; j++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - } - if (recover) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - TimeUnit.MILLISECONDS.sleep(300); - writer.abort(); - if (LOG.isDebugEnabled()) { - LOG.debug("Recovering Segments"); - } - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - Utils.ioResult(blplm.recoverIncompleteLogSegments()); - Utils.ioResult(blplm.asyncClose()); - if (LOG.isDebugEnabled()) { - LOG.debug("Recovered Segments"); - } - } else { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - writer.closeAndComplete(); - } - TimeUnit.MILLISECONDS.sleep(300); - } - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamReader.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamReader.java deleted file mode 100644 index e118e289ea5..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamReader.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.exceptions.EndOfStreamException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Test Case for {@link AppendOnlyStreamReader}. - */ -public class TestAppendOnlyStreamReader extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestAppendOnlyStreamReader.class); - - @Rule - public TestName testNames = new TestName(); - - // Simple test subroutine writes some records, reads some back, skips ahead, skips back. - public void skipForwardThenSkipBack(String name, DistributedLogConfiguration conf) throws Exception { - DistributedLogManager dlmwrite = createNewDLM(conf, name); - DistributedLogManager dlmreader = createNewDLM(conf, name); - - long txid = 1; - AppendOnlyStreamWriter writer = dlmwrite.getAppendOnlyStreamWriter(); - writer.write(DLMTestUtil.repeatString("abc", 5).getBytes()); - writer.write(DLMTestUtil.repeatString("abc", 5).getBytes()); - writer.write(DLMTestUtil.repeatString("def", 5).getBytes()); - writer.write(DLMTestUtil.repeatString("def", 5).getBytes()); - writer.write(DLMTestUtil.repeatString("ghi", 5).getBytes()); - writer.write(DLMTestUtil.repeatString("ghi", 5).getBytes()); - writer.force(false); - writer.close(); - - AppendOnlyStreamReader reader = dlmreader.getAppendOnlyStreamReader(); - byte[] bytesIn = new byte[30]; - - byte[] bytes1 = DLMTestUtil.repeatString("abc", 10).getBytes(); - byte[] bytes2 = DLMTestUtil.repeatString("def", 10).getBytes(); - byte[] bytes3 = DLMTestUtil.repeatString("ghi", 10).getBytes(); - - int read = reader.read(bytesIn, 0, 30); - assertEquals(30, read); - assertTrue(Arrays.equals(bytes1, bytesIn)); - - reader.skipTo(60); - read = reader.read(bytesIn, 0, 30); - assertEquals(30, read); - assertTrue(Arrays.equals(bytes3, bytesIn)); - - reader.skipTo(30); - read = reader.read(bytesIn, 0, 30); - assertEquals(30, read); - assertTrue(Arrays.equals(bytes2, bytesIn)); - } - - @Test(timeout = 60000) - public void testSkipToSkipsBytesWithImmediateFlush() throws Exception { - String name = testNames.getMethodName(); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - - skipForwardThenSkipBack(name, confLocal); - } - - @Test(timeout = 60000) - public void testSkipToSkipsBytesWithLargerLogRecords() throws Exception { - String name = testNames.getMethodName(); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(1024 * 100); - confLocal.setPeriodicFlushFrequencyMilliSeconds(1000 * 60); - - skipForwardThenSkipBack(name, confLocal); - } - - @Test(timeout = 60000) - public void testSkipToSkipsBytesUntilEndOfStream() throws Exception { - String name = testNames.getMethodName(); - - DistributedLogManager dlmwrite = createNewDLM(conf, name); - DistributedLogManager dlmreader = createNewDLM(conf, name); - - long txid = 1; - AppendOnlyStreamWriter writer = dlmwrite.getAppendOnlyStreamWriter(); - writer.write(DLMTestUtil.repeatString("abc", 5).getBytes()); - writer.markEndOfStream(); - writer.force(false); - writer.close(); - - AppendOnlyStreamReader reader = dlmreader.getAppendOnlyStreamReader(); - byte[] bytesIn = new byte[9]; - - int read = reader.read(bytesIn, 0, 9); - assertEquals(9, read); - assertTrue(Arrays.equals(DLMTestUtil.repeatString("abc", 3).getBytes(), bytesIn)); - - assertTrue(reader.skipTo(15)); - - try { - read = reader.read(bytesIn, 0, 1); - fail("Should have thrown"); - } catch (EndOfStreamException ex) { - } - - assertTrue(reader.skipTo(0)); - - try { - reader.skipTo(16); - fail("Should have thrown"); - } catch (EndOfStreamException ex) { - } - } - - @Test(timeout = 60000) - public void testSkipToreturnsFalseIfPositionDoesNotExistYetForUnSealedStream() throws Exception { - String name = testNames.getMethodName(); - - DistributedLogManager dlmwrite = createNewDLM(conf, name); - DistributedLogManager dlmreader = createNewDLM(conf, name); - - long txid = 1; - AppendOnlyStreamWriter writer = dlmwrite.getAppendOnlyStreamWriter(); - writer.write(DLMTestUtil.repeatString("abc", 5).getBytes()); - writer.close(); - - final AppendOnlyStreamReader reader = dlmreader.getAppendOnlyStreamReader(); - byte[] bytesIn = new byte[9]; - - int read = reader.read(bytesIn, 0, 9); - assertEquals(9, read); - assertTrue(Arrays.equals(DLMTestUtil.repeatString("abc", 3).getBytes(), bytesIn)); - - assertFalse(reader.skipTo(16)); - assertFalse(reader.skipTo(16)); - - AppendOnlyStreamWriter writer2 = dlmwrite.getAppendOnlyStreamWriter(); - writer2.write(DLMTestUtil.repeatString("abc", 5).getBytes()); - writer2.close(); - - assertTrue(reader.skipTo(16)); - - byte[] bytesIn2 = new byte[5]; - read = reader.read(bytesIn2, 0, 5); - assertEquals(5, read); - assertTrue(Arrays.equals("bcabc".getBytes(), bytesIn2)); - } - - @Test(timeout = 60000) - public void testSkipToForNoPositionChange() throws Exception { - String name = testNames.getMethodName(); - - DistributedLogManager dlmwrite = createNewDLM(conf, name); - DistributedLogManager dlmreader = createNewDLM(conf, name); - - long txid = 1; - AppendOnlyStreamWriter writer = dlmwrite.getAppendOnlyStreamWriter(); - writer.write(DLMTestUtil.repeatString("abc", 5).getBytes()); - writer.close(); - - final AppendOnlyStreamReader reader = dlmreader.getAppendOnlyStreamReader(); - - assertTrue(reader.skipTo(0)); - - byte[] bytesIn = new byte[4]; - int read = reader.read(bytesIn, 0, 4); - assertEquals(4, read); - assertEquals("abca", new String(bytesIn)); - - assertTrue(reader.skipTo(reader.position())); - - assertTrue(reader.skipTo(1)); - - read = reader.read(bytesIn, 0, 4); - assertEquals(4, read); - assertEquals("bcab", new String(bytesIn)); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamWriter.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamWriter.java deleted file mode 100644 index 0608bd6bc4a..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAppendOnlyStreamWriter.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; - -import java.io.ByteArrayInputStream; -import java.net.URI; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.exceptions.BKTransmitException; -import org.apache.distributedlog.exceptions.EndOfStreamException; -import org.apache.distributedlog.exceptions.WriteException; -import org.apache.distributedlog.util.FailpointUtils; -import org.apache.distributedlog.util.Utils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test Case for {@link AppendOnlyStreamWriter}. - */ -public class TestAppendOnlyStreamWriter extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestAppendOnlyStreamWriter.class); - - @Rule - public TestName testNames = new TestName(); - - @Test(timeout = 60000) - public void testBasicReadAndWriteBehavior() throws Exception { - String name = testNames.getMethodName(); - DistributedLogManager dlmwrite = createNewDLM(conf, name); - DistributedLogManager dlmreader = createNewDLM(conf, name); - byte[] byteStream = DLMTestUtil.repeatString("abc", 51).getBytes(); - - long txid = 1; - AppendOnlyStreamWriter writer = dlmwrite.getAppendOnlyStreamWriter(); - writer.write(DLMTestUtil.repeatString("abc", 11).getBytes()); - writer.write(DLMTestUtil.repeatString("abc", 40).getBytes()); - writer.force(false); - writer.close(); - AppendOnlyStreamReader reader = dlmreader.getAppendOnlyStreamReader(); - - byte[] bytesIn = new byte[byteStream.length]; - int read = reader.read(bytesIn, 0, 23); - assertEquals(23, read); - read = reader.read(bytesIn, 23, 31); - assertEquals(read, 31); - byte[] bytesInTemp = new byte[byteStream.length]; - read = reader.read(bytesInTemp, 0, byteStream.length); - assertEquals(read, byteStream.length - 23 - 31); - read = new ByteArrayInputStream(bytesInTemp).read(bytesIn, 23 + 31, byteStream.length - 23 - 31); - assertEquals(read, byteStream.length - 23 - 31); - assertArrayEquals(bytesIn, byteStream); - reader.close(); - dlmreader.close(); - dlmwrite.close(); - } - - @Test(timeout = 60000) - public void testWriteFutureDoesNotCompleteUntilWritePersisted() throws Exception { - String name = testNames.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.setPeriodicFlushFrequencyMilliSeconds(Integer.MAX_VALUE); - conf.setImmediateFlushEnabled(false); - - DistributedLogManager dlmwriter = createNewDLM(conf, name); - DistributedLogManager dlmreader = createNewDLM(conf, name); - byte[] byteStream = DLMTestUtil.repeatString("abc", 51).getBytes(); - - // Can't reliably test the future is not completed until fsync is called, since writer.force may just - // happen very quickly. But we can test that the mechanics of the future write and api are basically - // correct. - AppendOnlyStreamWriter writer = dlmwriter.getAppendOnlyStreamWriter(); - CompletableFuture dlsnFuture = writer.write(DLMTestUtil.repeatString("abc", 11).getBytes()); - - // The real problem is the fsync completes before writes are submitted, so it never takes effect. - Thread.sleep(1000); - assertFalse(dlsnFuture.isDone()); - writer.force(false); - // Must not throw. - Utils.ioResult(dlsnFuture, 5, TimeUnit.SECONDS); - writer.close(); - dlmwriter.close(); - - AppendOnlyStreamReader reader = dlmreader.getAppendOnlyStreamReader(); - byte[] bytesIn = new byte[byteStream.length]; - int read = reader.read(bytesIn, 0, 31); - assertEquals(31, read); - reader.close(); - dlmreader.close(); - } - - @Test(timeout = 60000) - public void testPositionUpdatesOnlyAfterWriteCompletion() throws Exception { - String name = testNames.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.setPeriodicFlushFrequencyMilliSeconds(10 * 1000); - conf.setImmediateFlushEnabled(false); - - DistributedLogManager dlmwriter = createNewDLM(conf, name); - DistributedLogManager dlmreader = createNewDLM(conf, name); - byte[] byteStream = DLMTestUtil.repeatString("abc", 11).getBytes(); - - // Can't reliably test the future is not completed until fsync is called, since writer.force may just - // happen very quickly. But we can test that the mechanics of the future write and api are basically - // correct. - AppendOnlyStreamWriter writer = dlmwriter.getAppendOnlyStreamWriter(); - CompletableFuture dlsnFuture = writer.write(byteStream); - Thread.sleep(100); - - // Write hasn't been persisted, position better not be updated. - assertFalse(dlsnFuture.isDone()); - assertEquals(0, writer.position()); - writer.force(false); - // Position guaranteed to be accurate after writer.force(). - assertEquals(byteStream.length, writer.position()); - - // Close writer. - writer.close(); - dlmwriter.close(); - - // Make sure we can read it. - AppendOnlyStreamReader reader = dlmreader.getAppendOnlyStreamReader(); - byte[] bytesIn = new byte[byteStream.length]; - int read = reader.read(bytesIn, 0, byteStream.length); - assertEquals(byteStream.length, read); - assertEquals(byteStream.length, reader.position()); - reader.close(); - dlmreader.close(); - } - - @Test(timeout = 60000) - public void testPositionDoesntUpdateBeforeWriteCompletion() throws Exception { - String name = testNames.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - - // Long flush time, but we don't wait for it. - conf.setPeriodicFlushFrequencyMilliSeconds(100 * 1000); - conf.setImmediateFlushEnabled(false); - conf.setOutputBufferSize(1024 * 1024); - - DistributedLogManager dlmwriter = createNewDLM(conf, name); - byte[] byteStream = DLMTestUtil.repeatString("abc", 11).getBytes(); - - AppendOnlyStreamWriter writer = dlmwriter.getAppendOnlyStreamWriter(); - assertEquals(0, writer.position()); - - // Much much less than the flush time, small enough not to slow down tests too much, just - // gives a little more confidence. - Thread.sleep(500); - CompletableFuture dlsnFuture = writer.write(byteStream); - assertEquals(0, writer.position()); - - writer.close(); - dlmwriter.close(); - } - - @Test(timeout = 60000) - public void testPositionUpdatesOnlyAfterWriteCompletionWithoutFsync() throws Exception { - String name = testNames.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.setPeriodicFlushFrequencyMilliSeconds(1 * 1000); - conf.setImmediateFlushEnabled(false); - conf.setOutputBufferSize(1024 * 1024); - - DistributedLogManager dlmwriter = createNewDLM(conf, name); - byte[] byteStream = DLMTestUtil.repeatString("abc", 11).getBytes(); - - AppendOnlyStreamWriter writer = dlmwriter.getAppendOnlyStreamWriter(); - assertEquals(0, writer.position()); - - Utils.ioResult(writer.write(byteStream)); - Thread.sleep(100); // let WriteCompleteListener have time to run - assertEquals(33, writer.position()); - - writer.close(); - dlmwriter.close(); - } - - @Test(timeout = 60000) - public void testWriterStartsAtTxidZeroForEmptyStream() throws Exception { - String name = testNames.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.setImmediateFlushEnabled(true); - conf.setOutputBufferSize(1024); - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(conf, name); - - URI uri = createDLMURI("/" + name); - Utils.ioResult(dlm.getWriterMetadataStore().getLog(uri, name, true, true)); - - // Log exists but is empty, better not throw. - AppendOnlyStreamWriter writer = dlm.getAppendOnlyStreamWriter(); - byte[] byteStream = DLMTestUtil.repeatString("a", 1025).getBytes(); - Utils.ioResult(writer.write(byteStream)); - - writer.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testOffsetGapAfterSegmentWriterFailure() throws Exception { - String name = testNames.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.setImmediateFlushEnabled(false); - conf.setPeriodicFlushFrequencyMilliSeconds(60 * 1000); - conf.setOutputBufferSize(1024 * 1024); - conf.setLogSegmentSequenceNumberValidationEnabled(false); - - final int writeLen = 5; - final int sectionWrites = 10; - long read = writeRecordsAndReadThemBackAfterInjectingAFailedTransmit(conf, name, writeLen, sectionWrites); - assertEquals((2 * sectionWrites + 1) * writeLen, read); - } - - @Test(timeout = 60000) - public void testNoOffsetGapAfterSegmentWriterFailure() throws Exception { - String name = testNames.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.setImmediateFlushEnabled(false); - conf.setPeriodicFlushFrequencyMilliSeconds(60 * 1000); - conf.setOutputBufferSize(1024 * 1024); - conf.setDisableRollingOnLogSegmentError(true); - - final int writeLen = 5; - final int sectionWrites = 10; - - try { - writeRecordsAndReadThemBackAfterInjectingAFailedTransmit(conf, name, writeLen, sectionWrites); - fail("should have thrown"); - } catch (BKTransmitException ex) { - } - - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(conf, name); - long length = dlm.getLastTxId(); - long read = read(dlm, length); - assertEquals(length, read); - } - - long writeRecordsAndReadThemBackAfterInjectingAFailedTransmit( - DistributedLogConfiguration conf, - String name, - int writeLen, - int sectionWrites) - throws Exception { - - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(conf, name); - - URI uri = createDLMURI("/" + name); - Utils.ioResult(dlm.getWriterMetadataStore().getLog(uri, name, true, true)); - - // Log exists but is empty, better not throw. - AppendOnlyStreamWriter writer = dlm.getAppendOnlyStreamWriter(); - byte[] byteStream = DLMTestUtil.repeatString("A", writeLen).getBytes(); - - // Log a hundred entries. Offset is advanced accordingly. - for (int i = 0; i < sectionWrites; i++) { - writer.write(byteStream); - } - writer.force(false); - - long read = read(dlm, 1 * sectionWrites * writeLen); - assertEquals(1 * sectionWrites * writeLen, read); - - // Now write another 100, but trigger failure during transmit. - for (int i = 0; i < sectionWrites; i++) { - writer.write(byteStream); - } - - try { - FailpointUtils.setFailpoint( - FailpointUtils.FailPointName.FP_TransmitFailGetBuffer, - FailpointUtils.FailPointActions.FailPointAction_Throw); - - writer.force(false); - fail("should have thown ⊙﹏⊙"); - } catch (WriteException we) { - } finally { - FailpointUtils.removeFailpoint( - FailpointUtils.FailPointName.FP_TransmitFailGetBuffer); - } - - // This actually fails because we try to close an errored out stream. - writer.write(byteStream); - - // Writing another 100 triggers offset gap. - for (int i = 0; i < sectionWrites; i++) { - writer.write(byteStream); - } - - writer.force(false); - writer.markEndOfStream(); - writer.close(); - - long length = dlm.getLastTxId(); - assertEquals(3 * sectionWrites * writeLen + 5, length); - read = read(dlm, length); - dlm.close(); - return read; - } - - long read(DistributedLogManager dlm, long n) throws Exception { - AppendOnlyStreamReader reader = dlm.getAppendOnlyStreamReader(); - byte[] bytesIn = new byte[1]; - long offset = 0; - try { - while (offset < n) { - int read = reader.read(bytesIn, 0, 1); - offset += read; - } - } catch (EndOfStreamException ex) { - LOG.info("Caught ex", ex); - } finally { - reader.close(); - } - return offset; - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncBulkWrite.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncBulkWrite.java deleted file mode 100644 index 71a945ec657..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncBulkWrite.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - - -import static org.apache.distributedlog.DLMTestUtil.validateFutureFailed; -import static org.apache.distributedlog.DLMTestUtil.validateFutureSucceededAndGetResult; -import static org.apache.distributedlog.LogRecord.MAX_LOGRECORDSET_SIZE; -import static org.apache.distributedlog.LogRecord.MAX_LOGRECORD_SIZE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.exceptions.LogRecordTooLongException; -import org.apache.distributedlog.exceptions.WriteCancelledException; -import org.apache.distributedlog.exceptions.WriteException; -import org.apache.distributedlog.util.FailpointUtils; -import org.apache.distributedlog.util.Utils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - - -/** - * Test cases for bulk writes. - */ -public class TestAsyncBulkWrite extends TestDistributedLogBase { - - static final Logger LOG = LoggerFactory.getLogger(TestAsyncBulkWrite.class); - - @Rule - public TestName runtime = new TestName(); - - protected final DistributedLogConfiguration testConf; - - public TestAsyncBulkWrite() { - this.testConf = new DistributedLogConfiguration(); - this.testConf.addConfiguration(conf); - this.testConf.setReaderIdleErrorThresholdMillis(1200000); - } - - /** - * Test Case for partial failure in a bulk write. - * Write a batch: 10 good records + 1 too large record + 10 good records. - * Expected: first 10 good records succeed, the too-large-record will be rejected, while - * the last 10 good records will be cancelled because their previous write is rejected. - */ - @Test(timeout = 60000) - public void testAsyncBulkWritePartialFailureBufferFailure() throws Exception { - String name = "distrlog-testAsyncBulkWritePartialFailure"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - final int goodRecs = 10; - - // Generate records: 10 good records, 1 too large record, 10 good records - final List records = DLMTestUtil.getLargeLogRecordInstanceList(1, goodRecs); - records.add(DLMTestUtil.getLogRecordInstance(goodRecs, MAX_LOGRECORD_SIZE + 1)); - records.addAll(DLMTestUtil.getLargeLogRecordInstanceList(1, goodRecs)); - - CompletableFuture>> futureResults = writer.writeBulk(records); - List> results = validateFutureSucceededAndGetResult(futureResults); - - // One future returned for each write. - assertEquals(2 * goodRecs + 1, results.size()); - - // First goodRecs are good. - for (int i = 0; i < goodRecs; i++) { - DLSN dlsn = validateFutureSucceededAndGetResult(results.get(i)); - } - - // First failure is log rec too big. - validateFutureFailed(results.get(goodRecs), LogRecordTooLongException.class); - - // Rest are WriteCancelledException. - for (int i = goodRecs + 1; i < 2 * goodRecs + 1; i++) { - validateFutureFailed(results.get(i), WriteCancelledException.class); - } - - writer.closeAndComplete(); - dlm.close(); - } - - /** - * Test Case for a total failure in a bulk write. - * Write 100 records as a batch. Inject failure on transmit and all records should be failed. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testAsyncBulkWriteTotalFailureTransmitFailure() throws Exception { - String name = "distrlog-testAsyncBulkWriteTotalFailureDueToTransmitFailure"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - final int batchSize = 100; - FailpointUtils.setFailpoint( - FailpointUtils.FailPointName.FP_TransmitComplete, - FailpointUtils.FailPointActions.FailPointAction_Default - ); - try { - // Since we don't hit MAX_TRANSMISSION_SIZE, the failure is triggered on final flush, which - // will enqueue cancel promises task to the ordered future pool. - checkAllSubmittedButFailed(writer, batchSize, 1024, 1); - } finally { - FailpointUtils.removeFailpoint( - FailpointUtils.FailPointName.FP_TransmitComplete - ); - } - - writer.abort(); - dlm.close(); - } - - /** - * Test Case: There is no log segment rolling when there is partial failure in async bulk write. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testAsyncBulkWriteNoLedgerRollWithPartialFailures() throws Exception { - String name = "distrlog-testAsyncBulkWriteNoLedgerRollWithPartialFailures"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - confLocal.setMaxLogSegmentBytes(1024); - confLocal.setLogSegmentRollingIntervalMinutes(0); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - // Write one record larger than max seg size. Ledger doesn't roll until next write. - int txid = 1; - LogRecord record = DLMTestUtil.getLogRecordInstance(txid++, 2048); - CompletableFuture result = writer.write(record); - DLSN dlsn = validateFutureSucceededAndGetResult(result); - assertEquals(1, dlsn.getLogSegmentSequenceNo()); - - // Write two more via bulk. Ledger doesn't roll because there's a partial failure. - List records = null; - CompletableFuture>> futureResults = null; - List> results = null; - records = new ArrayList(2); - records.add(DLMTestUtil.getLogRecordInstance(txid++, 2048)); - records.add(DLMTestUtil.getLogRecordInstance(txid++, MAX_LOGRECORD_SIZE + 1)); - futureResults = writer.writeBulk(records); - results = validateFutureSucceededAndGetResult(futureResults); - result = results.get(0); - dlsn = validateFutureSucceededAndGetResult(result); - assertEquals(1, dlsn.getLogSegmentSequenceNo()); - - // Now writer is in a bad state. - records = new ArrayList(1); - records.add(DLMTestUtil.getLogRecordInstance(txid++, 2048)); - futureResults = writer.writeBulk(records); - validateFutureFailed(futureResults, WriteException.class); - - writer.closeAndComplete(); - dlm.close(); - } - - /** - * Test Case: A large write batch will span records into multiple entries and ledgers. - * @throws Exception - */ - @Test(timeout = 60000) - public void testSimpleAsyncBulkWriteSpanningEntryAndLedger() throws Exception { - String name = "distrlog-testSimpleAsyncBulkWriteSpanningEntryAndLedger"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - int batchSize = 100; - int recSize = 1024; - - // First entry. - long ledgerIndex = 1; - long entryIndex = 0; - long slotIndex = 0; - long txIndex = 1; - checkAllSucceeded(writer, batchSize, recSize, ledgerIndex, entryIndex, slotIndex, txIndex); - - // New entry. - entryIndex++; - slotIndex = 0; - txIndex += batchSize; - checkAllSucceeded(writer, batchSize, recSize, ledgerIndex, entryIndex, slotIndex, txIndex); - - // Roll ledger. - ledgerIndex++; - entryIndex = 0; - slotIndex = 0; - txIndex += batchSize; - writer.closeAndComplete(); - writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - checkAllSucceeded(writer, batchSize, recSize, ledgerIndex, entryIndex, slotIndex, txIndex); - - writer.closeAndComplete(); - dlm.close(); - } - - /** - * Test Case: A large write batch will span multiple packets. - * @throws Exception - */ - @Test(timeout = 60000) - public void testAsyncBulkWriteSpanningPackets() throws Exception { - String name = "distrlog-testAsyncBulkWriteSpanningPackets"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - // First entry. - int numTransmissions = 4; - int recSize = 10 * 1024; - int batchSize = (numTransmissions * MAX_LOGRECORDSET_SIZE + 1) / recSize; - long ledgerIndex = 1; - long entryIndex = 0; - long slotIndex = 0; - long txIndex = 1; - DLSN dlsn = checkAllSucceeded(writer, batchSize, recSize, ledgerIndex, entryIndex, slotIndex, txIndex); - assertEquals(4, dlsn.getEntryId()); - assertEquals(1, dlsn.getLogSegmentSequenceNo()); - - writer.closeAndComplete(); - dlm.close(); - } - - /** - * Test Case: Test Transmit Failures when a large write batch spans multiple packets. - * @throws Exception - */ - @Test(timeout = 60000) - public void testAsyncBulkWriteSpanningPacketsWithTransmitFailure() throws Exception { - String name = "distrlog-testAsyncBulkWriteSpanningPacketsWithTransmitFailure"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - // First entry. - int numTransmissions = 4; - int recSize = 10 * 1024; - int batchSize = (numTransmissions * MAX_LOGRECORDSET_SIZE + 1) / recSize; - long ledgerIndex = 1; - long entryIndex = 0; - long slotIndex = 0; - long txIndex = 1; - - DLSN dlsn = checkAllSucceeded(writer, batchSize, recSize, ledgerIndex, entryIndex, slotIndex, txIndex); - assertEquals(4, dlsn.getEntryId()); - assertEquals(1, dlsn.getLogSegmentSequenceNo()); - - FailpointUtils.setFailpoint( - FailpointUtils.FailPointName.FP_TransmitComplete, - FailpointUtils.FailPointActions.FailPointAction_Default - ); - - try { - checkAllSubmittedButFailed(writer, batchSize, recSize, 1); - } finally { - FailpointUtils.removeFailpoint( - FailpointUtils.FailPointName.FP_TransmitComplete - ); - } - writer.abort(); - dlm.close(); - } - - private DLSN checkAllSucceeded(BKAsyncLogWriter writer, - int batchSize, - int recSize, - long ledgerIndex, - long entryIndex, - long slotIndex, - long txIndex) throws Exception { - - List records = DLMTestUtil.getLogRecordInstanceList(txIndex, batchSize, recSize); - CompletableFuture>> futureResults = writer.writeBulk(records); - assertNotNull(futureResults); - List> results = Utils.ioResult(futureResults, 10, TimeUnit.SECONDS); - assertNotNull(results); - assertEquals(results.size(), records.size()); - long prevEntryId = 0; - DLSN lastDlsn = null; - for (CompletableFuture result : results) { - DLSN dlsn = Utils.ioResult(result, 10, TimeUnit.SECONDS); - lastDlsn = dlsn; - - // If we cross a transmission boundary, slot id gets reset. - if (dlsn.getEntryId() > prevEntryId) { - slotIndex = 0; - } - assertEquals(ledgerIndex, dlsn.getLogSegmentSequenceNo()); - assertEquals(slotIndex, dlsn.getSlotId()); - slotIndex++; - prevEntryId = dlsn.getEntryId(); - } - return lastDlsn; - } - - private void checkAllSubmittedButFailed(BKAsyncLogWriter writer, - int batchSize, - int recSize, - long txIndex) throws Exception { - - List records = DLMTestUtil.getLogRecordInstanceList(txIndex, batchSize, recSize); - CompletableFuture>> futureResults = writer.writeBulk(records); - assertNotNull(futureResults); - List> results = Utils.ioResult(futureResults, 10, TimeUnit.SECONDS); - assertNotNull(results); - assertEquals(results.size(), records.size()); - for (CompletableFuture result : results) { - validateFutureFailed(result, IOException.class); - } - } -} - diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderLock.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderLock.java deleted file mode 100644 index a4ceea79af3..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderLock.java +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.net.URI; -import java.util.ArrayList; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.common.concurrent.FutureEventListener; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.api.subscription.SubscriptionsStore; -import org.apache.distributedlog.exceptions.LockCancelledException; -import org.apache.distributedlog.exceptions.LockingException; -import org.apache.distributedlog.exceptions.OwnershipAcquireFailedException; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.lock.LockClosedException; -import org.apache.distributedlog.namespace.NamespaceDriver; -import org.apache.distributedlog.util.Utils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - - -/** - * TestAsyncReaderLock. - */ -public class TestAsyncReaderLock extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestAsyncReaderLock.class); - - @Rule - public TestName runtime = new TestName(); - - void assertAcquiredFlagsSet(boolean[] acquiredFlags, int endIndex) { - for (int i = 0; i < endIndex; i++) { - assertTrue("reader " + i + " should have acquired lock", acquiredFlags[i]); - } - for (int i = endIndex; i < acquiredFlags.length; i++) { - assertFalse("reader " + i + " should not have acquired lock", acquiredFlags[i]); - } - } - - @Test(timeout = 60000) - public void testReaderLockIfLockPathDoesntExist() throws Exception { - final String name = runtime.getMethodName(); - DistributedLogManager dlm = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.closeAndComplete(); - - CompletableFuture futureReader1 = dlm.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - BKAsyncLogReader reader1 = (BKAsyncLogReader) Utils.ioResult(futureReader1); - LogRecordWithDLSN record = Utils.ioResult(reader1.readNext()); - assertEquals(1L, record.getTransactionId()); - assertEquals(0L, record.getSequenceId()); - DLMTestUtil.verifyLogRecord(record); - - String readLockPath = reader1.readHandler.getReadLockPath(); - Utils.close(reader1); - - // simulate a old stream created without readlock path - NamespaceDriver driver = dlm.getNamespaceDriver(); - ((BKNamespaceDriver) driver).getWriterZKC().get().delete(readLockPath, -1); - CompletableFuture futureReader2 = dlm.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - AsyncLogReader reader2 = Utils.ioResult(futureReader2); - record = Utils.ioResult(reader2.readNext()); - assertEquals(1L, record.getTransactionId()); - assertEquals(0L, record.getSequenceId()); - DLMTestUtil.verifyLogRecord(record); - } - - @Test(timeout = 60000) - public void testReaderLockCloseInAcquireCallback() throws Exception { - final String name = runtime.getMethodName(); - DistributedLogManager dlm = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.closeAndComplete(); - - final CountDownLatch latch = new CountDownLatch(1); - - CompletableFuture futureReader1 = dlm.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - futureReader1 - .thenCompose( - reader -> reader.asyncClose() - .thenApply(result -> { - latch.countDown(); - return null; - })); - - latch.await(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReaderLockBackgroundReaderLockAcquire() throws Exception { - final String name = runtime.getMethodName(); - DistributedLogManager dlm = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.closeAndComplete(); - - CompletableFuture futureReader1 = dlm.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - AsyncLogReader reader1 = Utils.ioResult(futureReader1); - reader1.readNext(); - - final CountDownLatch acquiredLatch = new CountDownLatch(1); - final AtomicBoolean acquired = new AtomicBoolean(false); - Thread acquireThread = new Thread(new Runnable() { - @Override - public void run() { - CompletableFuture futureReader2 = null; - DistributedLogManager dlm2 = null; - try { - dlm2 = createNewDLM(conf, name); - futureReader2 = dlm2.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - AsyncLogReader reader2 = Utils.ioResult(futureReader2); - acquired.set(true); - acquiredLatch.countDown(); - } catch (Exception ex) { - fail("shouldn't reach here"); - } finally { - try { - dlm2.close(); - } catch (Exception ex) { - fail("shouldn't reach here"); - } - } - } - }, "acquire-thread"); - acquireThread.start(); - - Thread.sleep(1000); - assertEquals(false, acquired.get()); - Utils.close(reader1); - - acquiredLatch.await(); - assertEquals(true, acquired.get()); - dlm.close(); - } - - int countDefined(ArrayList> readers) { - int done = 0; - for (CompletableFuture futureReader : readers) { - if (futureReader.isDone()) { - done++; - } - } - return done; - } - - @Test(timeout = 60000) - public void testReaderLockManyLocks() throws Exception { - String name = runtime.getMethodName(); - DistributedLogManager dlm = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.write(DLMTestUtil.getLogRecordInstance(2L)); - writer.closeAndComplete(); - - int count = 5; - final CountDownLatch acquiredLatch = new CountDownLatch(count); - final ArrayList> readers = - new ArrayList>(count); - for (int i = 0; i < count; i++) { - readers.add(null); - } - final DistributedLogManager[] dlms = new DistributedLogManager[count]; - for (int i = 0; i < count; i++) { - dlms[i] = createNewDLM(conf, name); - readers.set(i, dlms[i].getAsyncLogReaderWithLock(DLSN.InitialDLSN)); - readers.get(i).whenComplete(new FutureEventListener() { - @Override - public void onSuccess(AsyncLogReader reader) { - acquiredLatch.countDown(); - reader.asyncClose(); - } - @Override - public void onFailure(Throwable cause) { - fail("acquire shouldnt have failed"); - } - }); - } - - acquiredLatch.await(); - for (int i = 0; i < count; i++) { - dlms[i].close(); - } - - dlm.close(); - } - - @Test(timeout = 60000) - public void testReaderLockDlmClosed() throws Exception { - String name = runtime.getMethodName(); - DistributedLogManager dlm0 = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm0.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.write(DLMTestUtil.getLogRecordInstance(2L)); - writer.closeAndComplete(); - - DistributedLogManager dlm1 = createNewDLM(conf, name); - CompletableFuture futureReader1 = dlm1.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - AsyncLogReader reader1 = Utils.ioResult(futureReader1); - - BKDistributedLogManager dlm2 = (BKDistributedLogManager) createNewDLM(conf, name); - CompletableFuture futureReader2 = dlm2.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - - dlm2.close(); - try { - Utils.ioResult(futureReader2); - fail("should have thrown exception!"); - } catch (CancellationException ce) { - } catch (LockClosedException ex) { - } catch (LockCancelledException ex) { - } - - Utils.close(reader1); - dlm0.close(); - dlm1.close(); - } - - @Test(timeout = 60000) - public void testReaderLockSessionExpires() throws Exception { - String name = runtime.getMethodName(); - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - Namespace ns0 = NamespaceBuilder.newBuilder() - .conf(conf) - .uri(uri) - .build(); - DistributedLogManager dlm0 = ns0.openLog(name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm0.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.write(DLMTestUtil.getLogRecordInstance(2L)); - writer.closeAndComplete(); - - Namespace ns1 = NamespaceBuilder.newBuilder() - .conf(conf) - .uri(uri) - .build(); - DistributedLogManager dlm1 = ns1.openLog(name); - CompletableFuture futureReader1 = dlm1.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - AsyncLogReader reader1 = Utils.ioResult(futureReader1); - ZooKeeperClientUtils.expireSession(((BKNamespaceDriver) - ns1.getNamespaceDriver()).getWriterZKC(), zkServers, 1000); - - // The result of expireSession is somewhat non-deterministic with this lock. - // It may fail with LockingException or it may succesfully reacquire, so for - // the moment rather than make it deterministic we accept either result. - boolean success = false; - try { - Utils.ioResult(reader1.readNext()); - success = true; - } catch (LockingException ex) { - } - if (success) { - Utils.ioResult(reader1.readNext()); - } - - Utils.close(reader1); - dlm0.close(); - ns0.close(); - dlm1.close(); - ns1.close(); - } - - @Test(timeout = 60000) - public void testReaderLockFutureCancelledWhileWaiting() throws Exception { - String name = runtime.getMethodName(); - DistributedLogManager dlm0 = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm0.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.write(DLMTestUtil.getLogRecordInstance(2L)); - writer.closeAndComplete(); - - DistributedLogManager dlm1 = createNewDLM(conf, name); - CompletableFuture futureReader1 = dlm1.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - AsyncLogReader reader1 = Utils.ioResult(futureReader1); - - DistributedLogManager dlm2 = createNewDLM(conf, name); - CompletableFuture futureReader2 = dlm2.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - try { - futureReader2.cancel(true); - Utils.ioResult(futureReader2); - fail("Should fail getting log reader as it is cancelled"); - } catch (CancellationException ce) { - } catch (LockClosedException ex) { - } catch (LockCancelledException ex) { - } catch (OwnershipAcquireFailedException oafe) { - } - - futureReader2 = dlm2.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - Utils.close(reader1); - - Utils.ioResult(futureReader2); - - dlm0.close(); - dlm1.close(); - dlm2.close(); - } - - @Test(timeout = 60000) - public void testReaderLockFutureCancelledWhileLocked() throws Exception { - String name = runtime.getMethodName(); - DistributedLogManager dlm0 = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm0.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.write(DLMTestUtil.getLogRecordInstance(2L)); - writer.closeAndComplete(); - - DistributedLogManager dlm1 = createNewDLM(conf, name); - CompletableFuture futureReader1 = dlm1.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - - // Must not throw or cancel or do anything bad, future already completed. - Utils.ioResult(futureReader1); - futureReader1.cancel(true); - AsyncLogReader reader1 = Utils.ioResult(futureReader1); - Utils.ioResult(reader1.readNext()); - - dlm0.close(); - dlm1.close(); - } - - @Test(timeout = 60000) - public void testReaderLockSharedDlmDoesNotConflict() throws Exception { - String name = runtime.getMethodName(); - DistributedLogManager dlm0 = createNewDLM(conf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm0.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.write(DLMTestUtil.getLogRecordInstance(2L)); - writer.closeAndComplete(); - - DistributedLogManager dlm1 = createNewDLM(conf, name); - CompletableFuture futureReader1 = dlm1.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - CompletableFuture futureReader2 = dlm1.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - - // Both use the same client id, so there's no lock conflict. Not necessarily ideal, but how the - // system currently works. - Utils.ioResult(futureReader1); - Utils.ioResult(futureReader2); - - dlm0.close(); - dlm1.close(); - } - - static class ReadRecordsListener implements FutureEventListener { - - final AtomicReference currentDLSN; - final String name; - final ExecutorService executorService; - - final CountDownLatch latch = new CountDownLatch(1); - boolean failed = false; - - public ReadRecordsListener(AtomicReference currentDLSN, - String name, - ExecutorService executorService) { - this.currentDLSN = currentDLSN; - this.name = name; - this.executorService = executorService; - } - public CountDownLatch getLatch() { - return latch; - } - public boolean failed() { - return failed; - } - public boolean done() { - return latch.getCount() == 0; - } - - @Override - public void onSuccess(final AsyncLogReader reader) { - LOG.info("Reader {} is ready to read entries", name); - executorService.submit(new Runnable() { - @Override - public void run() { - readEntries(reader); - } - }); - } - - private void readEntries(AsyncLogReader reader) { - try { - for (int i = 0; i < 300; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - currentDLSN.set(record.getDlsn()); - } - } catch (Exception ex) { - failed = true; - } finally { - latch.countDown(); - } - } - - @Override - public void onFailure(Throwable cause) { - LOG.error("{} failed to open reader", name, cause); - failed = true; - latch.countDown(); - } - } - - @Test(timeout = 60000) - public void testReaderLockMultiReadersScenario() throws Exception { - final String name = runtime.getMethodName(); - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - - DistributedLogConfiguration localConf = new DistributedLogConfiguration(); - localConf.addConfiguration(conf); - localConf.setImmediateFlushEnabled(false); - localConf.setPeriodicFlushFrequencyMilliSeconds(60 * 1000); - localConf.setOutputBufferSize(0); - // Otherwise, we won't be able to run scheduled threads for readahead when we're in a callback. - localConf.setNumWorkerThreads(2); - localConf.setLockTimeout(Long.MAX_VALUE); - - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(localConf).uri(uri).clientId("main").build(); - - DistributedLogManager dlm0 = namespace.openLog(name); - DLMTestUtil.generateCompletedLogSegments(dlm0, localConf, 9, 100); - dlm0.close(); - - int recordCount = 0; - AtomicReference currentDLSN = new AtomicReference(DLSN.InitialDLSN); - - String clientId1 = "reader1"; - Namespace namespace1 = NamespaceBuilder.newBuilder() - .conf(localConf).uri(uri).clientId(clientId1).build(); - DistributedLogManager dlm1 = namespace1.openLog(name); - String clientId2 = "reader2"; - Namespace namespace2 = NamespaceBuilder.newBuilder() - .conf(localConf).uri(uri).clientId(clientId2).build(); - DistributedLogManager dlm2 = namespace2.openLog(name); - String clientId3 = "reader3"; - Namespace namespace3 = NamespaceBuilder.newBuilder() - .conf(localConf).uri(uri).clientId(clientId3).build(); - DistributedLogManager dlm3 = namespace3.openLog(name); - - LOG.info("{} is opening reader on stream {}", clientId1, name); - CompletableFuture futureReader1 = dlm1.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - AsyncLogReader reader1 = Utils.ioResult(futureReader1); - LOG.info("{} opened reader on stream {}", clientId1, name); - - LOG.info("{} is opening reader on stream {}", clientId2, name); - CompletableFuture futureReader2 = dlm2.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - LOG.info("{} is opening reader on stream {}", clientId3, name); - CompletableFuture futureReader3 = dlm3.getAsyncLogReaderWithLock(DLSN.InitialDLSN); - - ExecutorService executorService = Executors.newCachedThreadPool(); - - ReadRecordsListener listener2 = - new ReadRecordsListener(currentDLSN, clientId2, executorService); - ReadRecordsListener listener3 = - new ReadRecordsListener(currentDLSN, clientId3, executorService); - futureReader2.whenComplete(listener2); - futureReader3.whenComplete(listener3); - - // Get reader1 and start reading. - for ( ; recordCount < 200; recordCount++) { - LogRecordWithDLSN record = Utils.ioResult(reader1.readNext()); - currentDLSN.set(record.getDlsn()); - } - - // Take a break, reader2 decides to stop waiting and cancels. - Thread.sleep(1000); - assertFalse(listener2.done()); - futureReader2.cancel(true); - listener2.getLatch().await(); - assertTrue(listener2.done()); - assertTrue(listener2.failed()); - - // Reader1 starts reading again. - for (; recordCount < 300; recordCount++) { - LogRecordWithDLSN record = Utils.ioResult(reader1.readNext()); - currentDLSN.set(record.getDlsn()); - } - - // Reader1 is done, someone else can take over. Since reader2 was - // aborted, reader3 should take its place. - assertFalse(listener3.done()); - Utils.close(reader1); - listener3.getLatch().await(); - assertTrue(listener3.done()); - assertFalse(listener3.failed()); - - assertEquals(new DLSN(3, 99, 0), currentDLSN.get()); - - try { - Utils.ioResult(futureReader2); - } catch (Exception ex) { - // Can't get this one to close it--the dlm will take care of it. - } - - Utils.close(Utils.ioResult(futureReader3)); - - dlm1.close(); - namespace1.close(); - dlm2.close(); - namespace2.close(); - dlm3.close(); - namespace3.close(); - - executorService.shutdown(); - } - - @Test(timeout = 60000) - public void testAsyncReadWithSubscriberId() throws Exception { - String name = "distrlog-asyncread-with-sbuscriber-id"; - String subscriberId = "asyncreader"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - - DLSN readDLSN = DLSN.InitialDLSN; - - int txid = 1; - for (long i = 0; i < 3; i++) { - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 10; j++) { - DLSN dlsn = Utils.ioResult(writer.write(DLMTestUtil.getEmptyLogRecordInstance(txid++))); - if (i == 1 && j == 1L) { - readDLSN = dlsn; - } - } - writer.closeAndComplete(); - } - - BKAsyncLogReader reader0 = (BKAsyncLogReader) Utils.ioResult(dlm.getAsyncLogReaderWithLock(subscriberId)); - assertEquals(DLSN.NonInclusiveLowerBound, reader0.getStartDLSN()); - long numTxns = 0; - LogRecordWithDLSN record = Utils.ioResult(reader0.readNext()); - while (null != record) { - DLMTestUtil.verifyEmptyLogRecord(record); - ++numTxns; - assertEquals(numTxns, record.getTransactionId()); - assertEquals(record.getTransactionId() - 1, record.getSequenceId()); - - if (txid - 1 == numTxns) { - break; - } - record = Utils.ioResult(reader0.readNext()); - } - assertEquals(txid - 1, numTxns); - Utils.close(reader0); - - SubscriptionsStore subscriptionsStore = dlm.getSubscriptionsStore(); - Utils.ioResult(subscriptionsStore.advanceCommitPosition(subscriberId, readDLSN)); - BKAsyncLogReader reader1 = (BKAsyncLogReader) Utils.ioResult(dlm.getAsyncLogReaderWithLock(subscriberId)); - assertEquals(readDLSN, reader1.getStartDLSN()); - numTxns = 0; - long startTxID = 10L; - record = Utils.ioResult(reader1.readNext()); - while (null != record) { - DLMTestUtil.verifyEmptyLogRecord(record); - ++numTxns; - ++startTxID; - assertEquals(startTxID, record.getTransactionId()); - assertEquals(record.getTransactionId() - 1L, record.getSequenceId()); - - if (startTxID == txid - 1) { - break; - } - record = Utils.ioResult(reader1.readNext()); - } - assertEquals(txid - 1, startTxID); - assertEquals(20, numTxns); - Utils.close(reader1); - - dlm.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java deleted file mode 100644 index 70c9b0dc32c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java +++ /dev/null @@ -1,2226 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.distributedlog.DLMTestUtil.validateFutureFailed; -import static org.apache.distributedlog.LogRecord.MAX_LOGRECORD_SIZE; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.base.Stopwatch; -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import java.io.IOException; -import java.net.URI; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.concurrent.FutureEventListener; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.feature.FixedValueFeature; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.api.LogWriter; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.common.config.ConcurrentBaseConfiguration; -import org.apache.distributedlog.common.config.ConcurrentConstConfiguration; -import org.apache.distributedlog.config.DynamicDistributedLogConfiguration; -import org.apache.distributedlog.exceptions.BKTransmitException; -import org.apache.distributedlog.exceptions.DLIllegalStateException; -import org.apache.distributedlog.exceptions.EndOfStreamException; -import org.apache.distributedlog.exceptions.IdleReaderException; -import org.apache.distributedlog.exceptions.LockingException; -import org.apache.distributedlog.exceptions.LogRecordTooLongException; -import org.apache.distributedlog.exceptions.OverCapacityException; -import org.apache.distributedlog.exceptions.ReadCancelledException; -import org.apache.distributedlog.exceptions.WriteException; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.io.CompressionCodec; -import org.apache.distributedlog.lock.DistributedLock; -import org.apache.distributedlog.util.FailpointUtils; -import org.apache.distributedlog.util.SimplePermitLimiter; -import org.apache.distributedlog.util.Utils; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for AsyncReaderWriter. - */ -public class TestAsyncReaderWriter extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestAsyncReaderWriter.class); - - protected DistributedLogConfiguration testConf; - - public TestAsyncReaderWriter() { - this.testConf = new DistributedLogConfiguration(); - this.testConf.loadConf(conf); - this.testConf.setReaderIdleErrorThresholdMillis(1200000); - this.testConf.setReadAheadWaitTimeOnEndOfStream(20); - } - - @Rule - public TestName runtime = new TestName(); - - /** - * Test writing control records to writers: writers should be able to write control records, and - * the readers should skip control records while reading. - */ - @Test(timeout = 60000) - public void testWriteControlRecord() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - // Write 3 log segments. For each log segments, write one control record and nine user records. - int txid = 1; - for (long i = 0; i < 3; i++) { - final long currentLogSegmentSeqNo = i + 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - DLSN dlsn = Utils.ioResult(writer.writeControlRecord(new LogRecord(txid++, "control".getBytes(UTF_8)))); - assertEquals(currentLogSegmentSeqNo, dlsn.getLogSegmentSequenceNo()); - assertEquals(0, dlsn.getEntryId()); - assertEquals(0, dlsn.getSlotId()); - for (long j = 1; j < 10; j++) { - final LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - Utils.ioResult(writer.write(record)); - } - writer.closeAndComplete(); - } - dlm.close(); - - // Read all the written data: It should skip control records and only return user records. - DistributedLogManager readDlm = createNewDLM(confLocal, name); - LogReader reader = readDlm.getInputStream(1); - - long numTrans = 0; - long expectedTxId = 2; - LogRecord record = reader.readNext(false); - while (null != record) { - DLMTestUtil.verifyLargeLogRecord(record); - numTrans++; - assertEquals(expectedTxId, record.getTransactionId()); - if (expectedTxId % 10 == 0) { - expectedTxId += 2; - } else { - ++expectedTxId; - } - record = reader.readNext(false); - } - reader.close(); - assertEquals(3 * 9, numTrans); - assertEquals(3 * 9, readDlm.getLogRecordCount()); - readDlm.close(); - } - - @Test(timeout = 60000) - public void testAsyncWritePendingWritesAbortedWhenLedgerRollTriggerFails() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - confLocal.setMaxLogSegmentBytes(1024); - confLocal.setLogSegmentRollingIntervalMinutes(0); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - // Write one record larger than max seg size. Ledger doesn't roll until next write. - int txid = 1; - LogRecord record = DLMTestUtil.getLogRecordInstance(txid++, 2048); - CompletableFuture result = writer.write(record); - DLSN dlsn = Utils.ioResult(result, 10, TimeUnit.SECONDS); - assertEquals(1, dlsn.getLogSegmentSequenceNo()); - - record = DLMTestUtil.getLogRecordInstance(txid++, MAX_LOGRECORD_SIZE + 1); - result = writer.write(record); - validateFutureFailed(result, LogRecordTooLongException.class); - - record = DLMTestUtil.getLogRecordInstance(txid++, MAX_LOGRECORD_SIZE + 1); - result = writer.write(record); - validateFutureFailed(result, WriteException.class); - - record = DLMTestUtil.getLogRecordInstance(txid++, MAX_LOGRECORD_SIZE + 1); - result = writer.write(record); - validateFutureFailed(result, WriteException.class); - - writer.closeAndComplete(); - dlm.close(); - } - - /** - * Test Case: Simple Async Writes. Writes 30 records. They should be written correctly. - * @throws Exception - */ - @Test(timeout = 60000) - public void testSimpleAsyncWrite() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - DistributedLogManager dlm = createNewDLM(confLocal, name); - - final CountDownLatch syncLatch = new CountDownLatch(numLogSegments * numRecordsPerLogSegment); - final AtomicBoolean errorsFound = new AtomicBoolean(false); - final AtomicReference maxDLSN = new AtomicReference(DLSN.InvalidDLSN); - int txid = 1; - for (long i = 0; i < numLogSegments; i++) { - final long currentLogSegmentSeqNo = i + 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - for (long j = 0; j < numRecordsPerLogSegment; j++) { - final long currentEntryId = j; - final LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - CompletableFuture dlsnFuture = writer.write(record); - dlsnFuture.whenComplete(new FutureEventListener() { - @Override - public void onSuccess(DLSN value) { - if (value.getLogSegmentSequenceNo() != currentLogSegmentSeqNo) { - if (LOG.isDebugEnabled()) { - LOG.debug("LogSegmentSequenceNumber: {}, Expected {}", - value.getLogSegmentSequenceNo(), currentLogSegmentSeqNo); - } - errorsFound.set(true); - } - - if (value.getEntryId() != currentEntryId) { - if (LOG.isDebugEnabled()) { - LOG.debug("EntryId: {}, Expected {}", value.getEntryId(), currentEntryId); - } - errorsFound.set(true); - } - - if (value.compareTo(maxDLSN.get()) > 0) { - maxDLSN.set(value); - } - - syncLatch.countDown(); - if (LOG.isDebugEnabled()) { - LOG.debug("SyncLatch: {}", syncLatch.getCount()); - } - } - @Override - public void onFailure(Throwable cause) { - LOG.error("Encountered exception on writing record {} in log segment {}", - currentEntryId, currentLogSegmentSeqNo); - errorsFound.set(true); - } - }); - } - writer.closeAndComplete(); - } - - syncLatch.await(); - assertFalse("Should not encounter any errors for async writes", errorsFound.get()); - - LogRecordWithDLSN last = dlm.getLastLogRecord(); - assertEquals("Last DLSN" + last.getDlsn() + " isn't the maximum DLSN " + maxDLSN.get(), - last.getDlsn(), maxDLSN.get()); - assertEquals(last.getDlsn(), dlm.getLastDLSN()); - assertEquals(last.getDlsn(), Utils.ioResult(dlm.getLastDLSNAsync())); - DLMTestUtil.verifyLargeLogRecord(last); - - dlm.close(); - } - - /** - * Write records into numLogSegments log segments. - * Each log segment has numRecordsPerLogSegment records. - * - * @param dlm - * distributedlog manager - * @param numLogSegments - * number of log segments - * @param numRecordsPerLogSegment - * number records per log segment - * @param startTxId - * start tx id - * @return next tx id - */ - private static long writeRecords(DistributedLogManager dlm, - int numLogSegments, - int numRecordsPerLogSegment, - long startTxId, - boolean emptyRecord) throws IOException { - long txid = startTxId; - for (long i = 0; i < numLogSegments; i++) { - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= numRecordsPerLogSegment; j++) { - if (emptyRecord) { - writer.write(DLMTestUtil.getEmptyLogRecordInstance(txid++)); - } else { - writer.write(DLMTestUtil.getLargeLogRecordInstance(txid++)); - } - } - writer.closeAndComplete(); - } - return txid; - } - - /** - * Write numRecords records to the log, starting with startTxId. - * It flushes every flushPerNumRecords records. - * - * @param dlm - * distributedlog manager - * @param numRecords - * num records to write - * @param startTxId - * start tx id - * @param flushPerNumRecords - * number records to flush - * @return next tx id - * @throws IOException - */ - private static long writeLogSegment(DistributedLogManager dlm, - int numRecords, - long startTxId, - int flushPerNumRecords, - boolean emptyRecord) throws IOException { - long txid = startTxId; - LogWriter writer = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= numRecords; j++) { - if (emptyRecord) { - writer.write(DLMTestUtil.getEmptyLogRecordInstance(txid++)); - } else { - writer.write(DLMTestUtil.getLargeLogRecordInstance(txid++)); - } - if (j % flushPerNumRecords == 0) { - writer.flush(); - writer.commit(); - } - } - writer.flush(); - writer.commit(); - writer.close(); - return txid; - } - - private static void readNext(final AsyncLogReader reader, - final DLSN startPosition, - final long startSequenceId, - final boolean monotonic, - final CountDownLatch syncLatch, - final CountDownLatch completionLatch, - final AtomicBoolean errorsFound) { - CompletableFuture record = reader.readNext(); - record.whenComplete(new FutureEventListener() { - @Override - public void onSuccess(LogRecordWithDLSN value) { - try { - if (monotonic) { - assertEquals(startSequenceId, value.getSequenceId()); - } else { - assertTrue(value.getSequenceId() < 0); - assertTrue(value.getSequenceId() > startSequenceId); - } - LOG.info("Received record {} from {}", value, reader.getStreamName()); - assertTrue(!value.isControl()); - assertTrue(value.getDlsn().getSlotId() == 0); - assertTrue(value.getDlsn().compareTo(startPosition) >= 0); - DLMTestUtil.verifyLargeLogRecord(value); - } catch (Exception exc) { - if (LOG.isDebugEnabled()) { - LOG.debug("Exception Encountered when verifying log record {} : ", - value.getDlsn(), exc); - } - errorsFound.set(true); - completionLatch.countDown(); - return; - } - syncLatch.countDown(); - if (syncLatch.getCount() <= 0) { - completionLatch.countDown(); - } else { - TestAsyncReaderWriter.readNext( - reader, - value.getDlsn().getNextDLSN(), - monotonic ? value.getSequenceId() + 1 : value.getSequenceId(), - monotonic, - syncLatch, - completionLatch, - errorsFound); - } - } - @Override - public void onFailure(Throwable cause) { - LOG.error("Encountered Exception on reading {}", reader.getStreamName(), cause); - errorsFound.set(true); - completionLatch.countDown(); - } - }); - } - - void simpleAsyncReadTest(String name, DistributedLogConfiguration confLocal) throws Exception { - confLocal.setOutputBufferSize(1024); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(10); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - // Write 30 records: 3 log segments, 10 records per log segment - long txid = 1L; - txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, false); - // Write another log segment with 5 records and flush every 2 records - txid = writeLogSegment(dlm, 5, txid, 2, false); - - final AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - final CountDownLatch syncLatch = new CountDownLatch((int) (txid - 1)); - final CountDownLatch completionLatch = new CountDownLatch(1); - final AtomicBoolean errorsFound = new AtomicBoolean(false); - - boolean monotonic = LogSegmentMetadata.supportsSequenceId(confLocal.getDLLedgerMetadataLayoutVersion()); - TestAsyncReaderWriter.readNext( - reader, - DLSN.InvalidDLSN, - monotonic ? 0L : Long.MIN_VALUE, - monotonic, - syncLatch, - completionLatch, - errorsFound); - - completionLatch.await(); - assertFalse("Errors encountered on reading records", errorsFound.get()); - syncLatch.await(); - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testSimpleAsyncRead() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - simpleAsyncReadTest(name, confLocal); - } - - @Test(timeout = 60000) - public void testSimpleAsyncReadWriteWithMonitoredFuturePool() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setTaskExecutionWarnTimeMicros(1000); - confLocal.setEnableTaskExecutionStats(true); - simpleAsyncReadTest(name, confLocal); - } - - @Test(timeout = 60000) - public void testBulkAsyncRead() throws Exception { - String name = "distrlog-bulkasyncread"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadMaxRecords(10000); - confLocal.setReadAheadBatchSize(10); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 20; - - DistributedLogManager dlm = createNewDLM(confLocal, name); - writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, 1L, false); - - final AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InitialDLSN); - int expectedTxID = 1; - int numReads = 0; - while (expectedTxID <= numLogSegments * numRecordsPerLogSegment) { - if (expectedTxID == numLogSegments * numRecordsPerLogSegment) { - break; - } - List records = Utils.ioResult(reader.readBulk(20)); - LOG.info("Bulk read {} entries.", records.size()); - - assertTrue(records.size() >= 1); - for (LogRecordWithDLSN record : records) { - assertEquals(expectedTxID, record.getTransactionId()); - ++expectedTxID; - } - ++numReads; - } - - // we expect bulk read works - assertTrue(numReads < 60); - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testBulkAsyncReadWithWriteBatch() throws Exception { - String name = "distrlog-bulkasyncread-with-writebatch"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setOutputBufferSize(1024000); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadMaxRecords(10000); - confLocal.setReadAheadBatchSize(10); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 20; - - writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, 1L, false); - - final AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InitialDLSN); - int expectedTxID = 1; - for (long i = 0; i < 3; i++) { - // since we batched 20 entries into single bookkeeper entry - // we should be able to read 20 entries as a batch. - List records = Utils.ioResult(reader.readBulk(20)); - assertEquals(20, records.size()); - for (LogRecordWithDLSN record : records) { - assertEquals(expectedTxID, record.getTransactionId()); - ++expectedTxID; - } - } - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testAsyncReadEmptyRecords() throws Exception { - String name = "distrlog-simpleasyncreadempty"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(10); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - long txid = 1L; - // write 3 log segments, 10 records per log segment - txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, true); - // write another log segment with 5 records and flush every 2 records - txid = writeLogSegment(dlm, 5, txid, 2, true); - - AsyncLogReader asyncReader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - assertEquals("Expected stream name = " + name + " but " + asyncReader.getStreamName() + " found", - name, asyncReader.getStreamName()); - long numTrans = 0; - DLSN lastDLSN = DLSN.InvalidDLSN; - LogRecordWithDLSN record = Utils.ioResult(asyncReader.readNext()); - while (null != record) { - DLMTestUtil.verifyEmptyLogRecord(record); - assertEquals(0, record.getDlsn().getSlotId()); - assertTrue(record.getDlsn().compareTo(lastDLSN) > 0); - lastDLSN = record.getDlsn(); - numTrans++; - if (numTrans >= (txid - 1)) { - break; - } - record = Utils.ioResult(asyncReader.readNext()); - } - assertEquals((txid - 1), numTrans); - Utils.close(asyncReader); - dlm.close(); - } - - /** - * Test Async Read by positioning to a given position in the log. - * @throws Exception - */ - @Test(timeout = 60000) - public void testSimpleAsyncReadPosition() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(1024); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(10); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - long txid = 1L; - // write 3 log segments, 10 records per log segment - txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, false); - // write another log segment with 5 records - txid = writeLogSegment(dlm, 5, txid, Integer.MAX_VALUE, false); - - final CountDownLatch syncLatch = new CountDownLatch((int) (txid - 14)); - final CountDownLatch doneLatch = new CountDownLatch(1); - final AtomicBoolean errorsFound = new AtomicBoolean(false); - final AsyncLogReader reader = dlm.getAsyncLogReader(new DLSN(2, 2, 4)); - assertEquals(name, reader.getStreamName()); - - boolean monotonic = LogSegmentMetadata.supportsSequenceId(confLocal.getDLLedgerMetadataLayoutVersion()); - TestAsyncReaderWriter.readNext( - reader, - new DLSN(2, 3, 0), - monotonic ? 13L : Long.MIN_VALUE, - monotonic, - syncLatch, - doneLatch, - errorsFound); - - doneLatch.await(); - assertFalse("Errors found on reading records", errorsFound.get()); - syncLatch.await(); - - Utils.close(reader); - dlm.close(); - } - - /** - * Test write/read entries when immediate flush is disabled. - * @throws Exception - */ - @Test(timeout = 60000) - public void testSimpleAsyncReadWrite() throws Exception { - testSimpleAsyncReadWriteInternal(runtime.getMethodName(), false); - } - - /** - * Test write/read entries when immediate flush is enabled. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testSimpleAsyncReadWriteImmediateFlush() throws Exception { - testSimpleAsyncReadWriteInternal(runtime.getMethodName(), true); - } - - /** - * Test if entries written using log segment metadata that doesn't support enveloping - * can be read correctly by a reader supporting both. - *NOTE: An older reader cannot read enveloped entry, so we don't have a test case covering - * the other scenario. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testNoEnvelopeWriterEnvelopeReader() throws Exception { - testSimpleAsyncReadWriteInternal(runtime.getMethodName(), true, - LogSegmentMetadata.LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES.value - 1); - } - - static class WriteFutureEventListener implements FutureEventListener { - private final LogRecord record; - private final long currentLogSegmentSeqNo; - private final long currentEntryId; - private final CountDownLatch syncLatch; - private final AtomicBoolean errorsFound; - private final boolean verifyEntryId; - - WriteFutureEventListener(LogRecord record, - long currentLogSegmentSeqNo, - long currentEntryId, - CountDownLatch syncLatch, - AtomicBoolean errorsFound, - boolean verifyEntryId) { - this.record = record; - this.currentLogSegmentSeqNo = currentLogSegmentSeqNo; - this.currentEntryId = currentEntryId; - this.syncLatch = syncLatch; - this.errorsFound = errorsFound; - this.verifyEntryId = verifyEntryId; - } - - /** - * Invoked if the computation completes successfully. - */ - @Override - public void onSuccess(DLSN value) { - if (value.getLogSegmentSequenceNo() != currentLogSegmentSeqNo) { - LOG.error("Ledger Seq No: {}, Expected: {}", value.getLogSegmentSequenceNo(), currentLogSegmentSeqNo); - errorsFound.set(true); - } - - if (verifyEntryId && value.getEntryId() != currentEntryId) { - LOG.error("EntryId: {}, Expected: {}", value.getEntryId(), currentEntryId); - errorsFound.set(true); - } - syncLatch.countDown(); - } - - /** - * Invoked if the computation completes unsuccessfully. - */ - @Override - public void onFailure(Throwable cause) { - LOG.error("Encountered failures on writing record as (lid = {}, eid = {}) :", - currentLogSegmentSeqNo, currentEntryId, cause); - errorsFound.set(true); - syncLatch.countDown(); - } - } - - void testSimpleAsyncReadWriteInternal(String name, boolean immediateFlush) - throws Exception { - testSimpleAsyncReadWriteInternal(name, immediateFlush, - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - } - - void testSimpleAsyncReadWriteInternal(String name, boolean immediateFlush, - int logSegmentVersion) throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(10); - confLocal.setOutputBufferSize(1024); - confLocal.setDLLedgerMetadataLayoutVersion(logSegmentVersion); - confLocal.setImmediateFlushEnabled(immediateFlush); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - final CountDownLatch readLatch = new CountDownLatch(numLogSegments * numRecordsPerLogSegment); - final CountDownLatch readDoneLatch = new CountDownLatch(1); - final AtomicBoolean readErrors = new AtomicBoolean(false); - final CountDownLatch writeLatch = new CountDownLatch(numLogSegments * numRecordsPerLogSegment); - final AtomicBoolean writeErrors = new AtomicBoolean(false); - final AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - assertEquals(name, reader.getStreamName()); - - int txid = 1; - for (long i = 0; i < 3; i++) { - final long currentLogSegmentSeqNo = i + 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - for (long j = 0; j < 10; j++) { - final long currentEntryId = j; - final LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - CompletableFuture dlsnFuture = writer.write(record); - dlsnFuture.whenComplete(new WriteFutureEventListener( - record, currentLogSegmentSeqNo, currentEntryId, writeLatch, writeErrors, true)); - if (i == 0 && j == 0) { - boolean monotonic = LogSegmentMetadata.supportsSequenceId(logSegmentVersion); - TestAsyncReaderWriter.readNext( - reader, - DLSN.InvalidDLSN, - monotonic ? 0L : Long.MIN_VALUE, - monotonic, - readLatch, - readDoneLatch, - readErrors); - } - } - writer.closeAndComplete(); - } - - writeLatch.await(); - assertFalse("All writes should succeed", writeErrors.get()); - - readDoneLatch.await(); - assertFalse("All reads should succeed", readErrors.get()); - readLatch.await(); - - Utils.close(reader); - dlm.close(); - } - - - /** - * Test Case: starting reading when the streams don't exist. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testSimpleAsyncReadWriteStartEmpty() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(10); - confLocal.setOutputBufferSize(1024); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - DistributedLogManager dlm = createNewDLM(confLocal, name); - - final CountDownLatch readerReadyLatch = new CountDownLatch(1); - final CountDownLatch readerDoneLatch = new CountDownLatch(1); - final CountDownLatch readerSyncLatch = new CountDownLatch(numLogSegments * numRecordsPerLogSegment); - - final TestReader reader = new TestReader( - "test-reader", - dlm, - DLSN.InitialDLSN, - false, - 0, - readerReadyLatch, - readerSyncLatch, - readerDoneLatch); - - reader.start(); - - // Increase the probability of reader failure and retry - Thread.sleep(500); - - final AtomicBoolean writeErrors = new AtomicBoolean(false); - final CountDownLatch writeLatch = new CountDownLatch(30); - - int txid = 1; - for (long i = 0; i < 3; i++) { - final long currentLogSegmentSeqNo = i + 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - for (long j = 0; j < 10; j++) { - final long currentEntryId = j; - final LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - CompletableFuture dlsnFuture = writer.write(record); - dlsnFuture.whenComplete(new WriteFutureEventListener( - record, currentLogSegmentSeqNo, currentEntryId, writeLatch, writeErrors, true)); - } - writer.closeAndComplete(); - } - - writeLatch.await(); - assertFalse("All writes should succeed", writeErrors.get()); - - readerDoneLatch.await(); - assertFalse("Should not encounter errors during reading", reader.areErrorsFound()); - readerSyncLatch.await(); - - assertTrue("Should position reader at least once", reader.getNumReaderPositions().get() > 1); - reader.stop(); - dlm.close(); - } - - - /** - * Test Case: starting reading when the streams don't exist. - * {@link https://issues.apache.org/jira/browse/DL-42} - */ - @Ignore - @Test(timeout = 120000) - public void testSimpleAsyncReadWriteStartEmptyFactory() throws Exception { - // int count = 50; - int count = 1; - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(10); - confLocal.setOutputBufferSize(1024); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 1; - - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(confLocal).uri(uri).build(); - final DistributedLogManager[] dlms = new DistributedLogManager[count]; - final TestReader[] readers = new TestReader[count]; - final CountDownLatch readyLatch = new CountDownLatch(count); - final CountDownLatch[] syncLatches = new CountDownLatch[count]; - final CountDownLatch[] readerDoneLatches = new CountDownLatch[count]; - for (int s = 0; s < count; s++) { - dlms[s] = namespace.openLog(name + String.format("%d", s)); - readerDoneLatches[s] = new CountDownLatch(1); - syncLatches[s] = new CountDownLatch(numLogSegments * numRecordsPerLogSegment); - readers[s] = new TestReader("reader-" + s, - dlms[s], DLSN.InitialDLSN, false, 0, readyLatch, syncLatches[s], readerDoneLatches[s]); - readers[s].start(); - } - - // wait all readers were positioned at least once - readyLatch.await(); - - final CountDownLatch writeLatch = new CountDownLatch(3 * count); - final AtomicBoolean writeErrors = new AtomicBoolean(false); - - int txid = 1; - for (long i = 0; i < 3; i++) { - final long currentLogSegmentSeqNo = i + 1; - BKAsyncLogWriter[] writers = new BKAsyncLogWriter[count]; - for (int s = 0; s < count; s++) { - writers[s] = (BKAsyncLogWriter) (dlms[s].startAsyncLogSegmentNonPartitioned()); - } - for (long j = 0; j < 1; j++) { - final long currentEntryId = j; - final LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - for (int s = 0; s < count; s++) { - CompletableFuture dlsnFuture = writers[s].write(record); - dlsnFuture.whenComplete(new WriteFutureEventListener( - record, currentLogSegmentSeqNo, currentEntryId, writeLatch, writeErrors, true)); - } - } - for (int s = 0; s < count; s++) { - writers[s].closeAndComplete(); - } - } - - writeLatch.await(); - assertFalse("All writes should succeed", writeErrors.get()); - - for (int s = 0; s < count; s++) { - readerDoneLatches[s].await(); - assertFalse("Reader " + s + " should not encounter errors", readers[s].areErrorsFound()); - syncLatches[s].await(); - assertEquals(numLogSegments * numRecordsPerLogSegment, readers[s].getNumReads().get()); - assertTrue("Reader " + s + " should position at least once", readers[s].getNumReaderPositions().get() > 0); - } - - for (int s = 0; s < count; s++) { - readers[s].stop(); - dlms[s].close(); - } - } - - /** - * Flaky test fixed: readers need to be added to the pendingReaders. - * @throws Exception - */ - @Test(timeout = 300000) - public void testSimpleAsyncReadWriteSimulateErrors() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(10); - confLocal.setOutputBufferSize(1024); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 5; - int numRecordsPerLogSegment = 10; - - final CountDownLatch doneLatch = new CountDownLatch(1); - final CountDownLatch syncLatch = new CountDownLatch(numLogSegments * numRecordsPerLogSegment); - - TestReader reader = new TestReader( - "test-reader", - dlm, - DLSN.InitialDLSN, - true, - 0, - new CountDownLatch(1), - syncLatch, - doneLatch); - - reader.start(); - - final CountDownLatch writeLatch = new CountDownLatch(numLogSegments * numRecordsPerLogSegment); - final AtomicBoolean writeErrors = new AtomicBoolean(false); - - int txid = 1; - for (long i = 0; i < numLogSegments; i++) { - final long currentLogSegmentSeqNo = i + 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - for (long j = 0; j < numRecordsPerLogSegment; j++) { - final long currentEntryId = j; - final LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - CompletableFuture dlsnFuture = writer.write(record); - dlsnFuture.whenComplete(new WriteFutureEventListener( - record, currentLogSegmentSeqNo, currentEntryId, writeLatch, writeErrors, true)); - } - writer.closeAndComplete(); - } - - writeLatch.await(); - assertFalse("All writes should succeed", writeErrors.get()); - - doneLatch.await(); - assertFalse("Should not encounter errors during reading", reader.areErrorsFound()); - syncLatch.await(); - - assertTrue("Should position reader at least once", reader.getNumReaderPositions().get() > 1); - reader.stop(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testSimpleAsyncReadWritePiggyBack() throws Exception { - String name = runtime.getMethodName(); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setEnableReadAhead(true); - confLocal.setReadAheadWaitTime(500); - confLocal.setReadAheadBatchSize(10); - confLocal.setReadAheadMaxRecords(100); - confLocal.setOutputBufferSize(1024); - confLocal.setPeriodicFlushFrequencyMilliSeconds(100); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - final AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - final CountDownLatch readLatch = new CountDownLatch(30); - final CountDownLatch readDoneLatch = new CountDownLatch(1); - final AtomicBoolean readErrors = new AtomicBoolean(false); - final CountDownLatch writeLatch = new CountDownLatch(30); - final AtomicBoolean writeErrors = new AtomicBoolean(false); - - int txid = 1; - for (long i = 0; i < numLogSegments; i++) { - final long currentLogSegmentSeqNo = i + 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - for (long j = 0; j < numRecordsPerLogSegment; j++) { - Thread.sleep(50); - final LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - CompletableFuture dlsnFuture = writer.write(record); - dlsnFuture.whenComplete(new WriteFutureEventListener( - record, currentLogSegmentSeqNo, j, writeLatch, writeErrors, false)); - if (i == 0 && j == 0) { - boolean monotonic = - LogSegmentMetadata.supportsSequenceId(confLocal.getDLLedgerMetadataLayoutVersion()); - TestAsyncReaderWriter.readNext( - reader, - DLSN.InvalidDLSN, - monotonic ? 0L : Long.MIN_VALUE, - monotonic, - readLatch, - readDoneLatch, - readErrors); - } - } - writer.closeAndComplete(); - } - - writeLatch.await(); - assertFalse("All writes should succeed", writeErrors.get()); - - readDoneLatch.await(); - assertFalse("All reads should succeed", readErrors.get()); - readLatch.await(); - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testCancelReadRequestOnReaderClosed() throws Exception { - final String name = "distrlog-cancel-read-requests-on-reader-closed"; - - DistributedLogManager dlm = createNewDLM(testConf, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.closeAndComplete(); - - final AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InitialDLSN); - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertEquals(1L, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - - final CountDownLatch readLatch = new CountDownLatch(1); - final AtomicBoolean receiveExpectedException = new AtomicBoolean(false); - Thread readThread = new Thread(new Runnable() { - @Override - public void run() { - try { - Utils.ioResult(reader.readNext()); - } catch (ReadCancelledException rce) { - receiveExpectedException.set(true); - } catch (Throwable t) { - LOG.error("Receive unexpected exception on reading stream {} : ", name, t); - } - readLatch.countDown(); - } - }, "read-thread"); - readThread.start(); - - Thread.sleep(1000); - - // close reader should cancel the pending read next - Utils.close(reader); - - readLatch.await(); - readThread.join(); - - assertTrue("Read request should be cancelled.", receiveExpectedException.get()); - - // closed reader should reject any readNext - try { - Utils.ioResult(reader.readNext()); - fail("Reader should reject readNext if it is closed."); - } catch (ReadCancelledException rce) { - // expected - } - - dlm.close(); - } - - @Test(timeout = 60000) - public void testAsyncWriteWithMinDelayBetweenFlushes() throws Exception { - String name = "distrlog-asyncwrite-mindelay"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setMinDelayBetweenImmediateFlushMs(100); - DistributedLogManager dlm = createNewDLM(confLocal, name); - final Thread currentThread = Thread.currentThread(); - final int count = 5000; - final CountDownLatch syncLatch = new CountDownLatch(count); - int txid = 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - Stopwatch executionTime = Stopwatch.createStarted(); - for (long i = 0; i < count; i++) { - Thread.sleep(1); - final LogRecord record = DLMTestUtil.getLogRecordInstance(txid++); - CompletableFuture dlsnFuture = writer.write(record); - dlsnFuture.whenComplete(new FutureEventListener() { - @Override - public void onSuccess(DLSN value) { - syncLatch.countDown(); - if (LOG.isDebugEnabled()) { - LOG.debug("SyncLatch: {} ; DLSN: {} ", syncLatch.getCount(), value); - } - } - @Override - public void onFailure(Throwable cause) { - currentThread.interrupt(); - } - }); - } - - boolean success = false; - if (!(Thread.interrupted())) { - try { - success = syncLatch.await(10, TimeUnit.SECONDS); - } catch (InterruptedException exc) { - Thread.currentThread().interrupt(); - } - } - - // Abort, not graceful close, since the latter will - // flush as well, and may add an entry. - writer.abort(); - - executionTime.stop(); - assertTrue(!(Thread.interrupted())); - assertTrue(success); - - LogRecordWithDLSN last = dlm.getLastLogRecord(); - LOG.info("Last Entry {}; elapsed time {}", - last.getDlsn().getEntryId(), executionTime.elapsed(TimeUnit.MILLISECONDS)); - - // Regardless of how many records we wrote; the number of BK entries should always be bounded by the min delay. - // Since there are two flush processes--data flush and control flush, and since control flush may also end up - // flushing data if data is available, the upper bound is 2*(time/min_delay + 1) - assertTrue(last.getDlsn().getEntryId() <= ((executionTime.elapsed(TimeUnit.MILLISECONDS) - / confLocal.getMinDelayBetweenImmediateFlushMs() + 1)) * 2); - DLMTestUtil.verifyLogRecord(last); - - dlm.close(); - } - - @Test(timeout = 60000) - public void testAsyncWriteWithMinDelayBetweenFlushesFlushFailure() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setMinDelayBetweenImmediateFlushMs(1); - - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(confLocal).uri(uri).clientId("gabbagoo").build(); - DistributedLogManager dlm = namespace.openLog(name); - Namespace namespace1 = NamespaceBuilder.newBuilder() - .conf(confLocal).uri(uri).clientId("tortellini").build(); - DistributedLogManager dlm1 = namespace1.openLog(name); - - int txid = 1; - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - // First write succeeds since lock isnt checked until transmit, which is scheduled - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid++))); - writer.flushAndCommit(); - - BKLogSegmentWriter perStreamWriter = writer.getCachedLogWriter(); - DistributedLock lock = perStreamWriter.getLock(); - Utils.ioResult(lock.asyncClose()); - - // Get second writer, steal lock - BKAsyncLogWriter writer2 = (BKAsyncLogWriter) (dlm1.startAsyncLogSegmentNonPartitioned()); - - try { - // Succeeds, kicks off scheduked flush - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - - // Succeeds, kicks off scheduled flush - Thread.sleep(100); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid++))); - fail("should have thrown"); - } catch (LockingException ex) { - if (LOG.isDebugEnabled()) { - LOG.debug("caught exception ", ex); - } - } - - writer.close(); - dlm.close(); - } - - public void writeRecordsWithOutstandingWriteLimit(int stream, int global, boolean shouldFail) throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setPerWriterOutstandingWriteLimit(stream); - confLocal.setOutstandingWriteLimitDarkmode(false); - DistributedLogManager dlm; - if (global > -1) { - dlm = createNewDLM(confLocal, runtime.getMethodName(), - new SimplePermitLimiter(false, global, new NullStatsLogger(), true, new FixedValueFeature("", 0))); - } else { - dlm = createNewDLM(confLocal, runtime.getMethodName()); - } - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - ArrayList> results = new ArrayList>(1000); - for (int i = 0; i < 1000; i++) { - results.add(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - } - for (CompletableFuture result : results) { - try { - Utils.ioResult(result); - if (shouldFail) { - fail("should fail due to no outstanding writes permitted"); - } - } catch (OverCapacityException ex) { - assertTrue(shouldFail); - } - } - writer.closeAndComplete(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testOutstandingWriteLimitNoLimit() throws Exception { - writeRecordsWithOutstandingWriteLimit(-1, -1, false); - } - - @Test(timeout = 60000) - public void testOutstandingWriteLimitVeryHighLimit() throws Exception { - writeRecordsWithOutstandingWriteLimit(Integer.MAX_VALUE, Integer.MAX_VALUE, false); - } - - @Test(timeout = 60000) - public void testOutstandingWriteLimitBlockAllStreamLimit() throws Exception { - writeRecordsWithOutstandingWriteLimit(0, Integer.MAX_VALUE, true); - } - - @Test(timeout = 60000) - public void testOutstandingWriteLimitBlockAllGlobalLimit() throws Exception { - writeRecordsWithOutstandingWriteLimit(Integer.MAX_VALUE, 0, true); - } - - @Test(timeout = 60000) - public void testOutstandingWriteLimitBlockAllLimitWithDarkmode() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setPerWriterOutstandingWriteLimit(0); - confLocal.setOutstandingWriteLimitDarkmode(true); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - ArrayList> results = new ArrayList>(1000); - for (int i = 0; i < 1000; i++) { - results.add(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - } - for (CompletableFuture result : results) { - Utils.ioResult(result); - } - writer.closeAndComplete(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testCloseAndCompleteLogSegmentWhenStreamIsInError() throws Exception { - String name = "distrlog-close-and-complete-logsegment-when-stream-is-in-error"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - long txId = 1L; - for (int i = 0; i < 5; i++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - } - - BKLogSegmentWriter logWriter = writer.getCachedLogWriter(); - - BKNamespaceDriver driver = (BKNamespaceDriver) dlm.getNamespaceDriver(); - // fence the ledger - driver.getReaderBKC().get().openLedger(logWriter.getLogSegmentId(), - BookKeeper.DigestType.CRC32, confLocal.getBKDigestPW().getBytes(UTF_8)); - - try { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - fail("Should fail write to a fenced ledger with BKTransmitException"); - } catch (BKTransmitException bkte) { - // expected - } - - try { - writer.closeAndComplete(); - fail("Should fail to complete a log segment when its ledger is fenced"); - } catch (BKTransmitException bkte) { - // expected - } - - List segments = dlm.getLogSegments(); - assertEquals(1, segments.size()); - assertTrue(segments.get(0).isInProgress()); - - dlm.close(); - } - - @Test(timeout = 60000) - public void testCloseAndCompleteLogSegmentWhenCloseFailed() throws Exception { - String name = "distrlog-close-and-complete-logsegment-when-close-failed"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - long txId = 1L; - for (int i = 0; i < 5; i++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - } - - BKLogSegmentWriter logWriter = writer.getCachedLogWriter(); - - BKNamespaceDriver driver = (BKNamespaceDriver) dlm.getNamespaceDriver(); - // fence the ledger - driver.getReaderBKC().get().openLedger(logWriter.getLogSegmentId(), - BookKeeper.DigestType.CRC32, confLocal.getBKDigestPW().getBytes(UTF_8)); - - try { - // insert a write to detect the fencing state, to make test more robust. - writer.write(DLMTestUtil.getLogRecordInstance(txId++)); - writer.closeAndComplete(); - fail("Should fail to complete a log segment when its ledger is fenced"); - } catch (IOException ioe) { - // expected - LOG.error("Failed to close and complete log segment {} : ", logWriter.getFullyQualifiedLogSegment(), ioe); - } - - List segments = dlm.getLogSegments(); - assertEquals(1, segments.size()); - assertTrue(segments.get(0).isInProgress()); - - dlm.close(); - } - - private void testAsyncReadIdleErrorInternal(String name, - final int idleReaderErrorThreshold, - final boolean heartBeatUsingControlRecs, - final boolean simulateReaderStall) throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setReadAheadBatchSize(1); - confLocal.setReadAheadMaxRecords(1); - confLocal.setReaderIdleWarnThresholdMillis(0); - confLocal.setReaderIdleErrorThresholdMillis(idleReaderErrorThreshold); - final DistributedLogManager dlm = createNewDLM(confLocal, name); - final Thread currentThread = Thread.currentThread(); - final int segmentSize = 3; - final int numSegments = 3; - final CountDownLatch latch = new CountDownLatch(1); - final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - executor.schedule( - new Runnable() { - @Override - public void run() { - try { - int txid = 1; - for (long i = 0; i < numSegments; i++) { - long start = txid; - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= segmentSize; j++) { - writer.write(DLMTestUtil.getLargeLogRecordInstance(txid++)); - if ((i == 0) && (j == 1)) { - latch.countDown(); - } - } - - if (heartBeatUsingControlRecs) { - // There should be a control record such that - // wait time + commit time (BK) < Idle Reader Threshold - int threadSleepTime = idleReaderErrorThreshold - - 200 // BK commitTime - - 100; //safety margin - - for (int iter = 1; iter <= (2 * idleReaderErrorThreshold / threadSleepTime); iter++) { - Thread.sleep(threadSleepTime); - writer.write(DLMTestUtil.getLargeLogRecordInstance(txid, true)); - writer.flush(); - } - Thread.sleep(threadSleepTime); - } - - writer.closeAndComplete(); - if (!heartBeatUsingControlRecs) { - Thread.sleep(2 * idleReaderErrorThreshold); - } - } - } catch (Exception exc) { - if (!executor.isShutdown()) { - currentThread.interrupt(); - } - } - } - }, 0, TimeUnit.MILLISECONDS); - - latch.await(); - BKAsyncLogReader reader = (BKAsyncLogReader) dlm.getAsyncLogReader(DLSN.InitialDLSN); - if (simulateReaderStall) { - reader.disableProcessingReadRequests(); - } - boolean exceptionEncountered = false; - int recordCount = 0; - try { - while (true) { - CompletableFuture record = reader.readNext(); - Utils.ioResult(record); - recordCount++; - - if (recordCount >= segmentSize * numSegments) { - break; - } - } - } catch (IdleReaderException exc) { - exceptionEncountered = true; - } - - if (simulateReaderStall) { - assertTrue(exceptionEncountered); - } else if (heartBeatUsingControlRecs) { - assertFalse(exceptionEncountered); - Assert.assertEquals(segmentSize * numSegments, recordCount); - } else { - assertTrue(exceptionEncountered); - Assert.assertEquals(segmentSize, recordCount); - } - assertFalse(currentThread.isInterrupted()); - Utils.close(reader); - executor.shutdown(); - } - - @Test(timeout = 10000) - public void testAsyncReadIdleControlRecord() throws Exception { - String name = "distrlog-async-reader-idle-error-control"; - testAsyncReadIdleErrorInternal(name, 500, true, false); - } - - @Test(timeout = 10000) - public void testAsyncReadIdleError() throws Exception { - String name = "distrlog-async-reader-idle-error"; - testAsyncReadIdleErrorInternal(name, 1000, false, false); - } - - @Test(timeout = 10000) - public void testAsyncReadIdleError2() throws Exception { - String name = "distrlog-async-reader-idle-error-2"; - testAsyncReadIdleErrorInternal(name, 1000, true, true); - } - - @Test(timeout = 60000) - public void testReleaseLockAfterFailedToRecover() throws Exception { - String name = "release-lock-after-failed-to-recover"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setLockTimeout(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = - (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - writer.abort(); - - for (int i = 0; i < 2; i++) { - FailpointUtils.setFailpoint( - FailpointUtils.FailPointName.FP_RecoverIncompleteLogSegments, - FailpointUtils.FailPointActions.FailPointAction_Throw); - - try { - dlm.startAsyncLogSegmentNonPartitioned(); - fail("Should fail during recovering incomplete log segments"); - } catch (IOException ioe) { - // expected; - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_RecoverIncompleteLogSegments); - } - } - - writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - - List segments = dlm.getLogSegments(); - assertEquals(1, segments.size()); - assertFalse(segments.get(0).isInProgress()); - - writer.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testAsyncReadMissingLogSegmentsNotification() throws Exception { - String name = "distrlog-async-reader-missing-zk-notification"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setReadAheadBatchSize(1); - confLocal.setReadAheadMaxRecords(1); - confLocal.setReadLACLongPollTimeout(49); - confLocal.setReaderIdleWarnThresholdMillis(100); - confLocal.setReaderIdleErrorThresholdMillis(20000); - final DistributedLogManager dlm = createNewDLM(confLocal, name); - final Thread currentThread = Thread.currentThread(); - final int segmentSize = 10; - final int numSegments = 3; - final CountDownLatch latch = new CountDownLatch(1); - final CountDownLatch readLatch = new CountDownLatch(1); - final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - executor.schedule( - new Runnable() { - @Override - public void run() { - try { - int txid = 1; - for (long i = 0; i < numSegments; i++) { - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= segmentSize; j++) { - writer.write(DLMTestUtil.getLargeLogRecordInstance(txid++)); - if ((i == 0) && (j == 1)) { - latch.countDown(); - } else { - // wait for reader to start - readLatch.await(); - } - } - writer.closeAndComplete(); - Thread.sleep(100); - } - } catch (Exception exc) { - if (!executor.isShutdown()) { - currentThread.interrupt(); - } - } - } - }, 0, TimeUnit.MILLISECONDS); - - latch.await(); - BKAsyncLogReader reader = (BKAsyncLogReader) dlm.getAsyncLogReader(DLSN.InitialDLSN); - reader.disableReadAheadLogSegmentsNotification(); - boolean exceptionEncountered = false; - int recordCount = 0; - try { - while (true) { - CompletableFuture record = reader.readNext(); - Utils.ioResult(record); - if (recordCount == 0) { - readLatch.countDown(); - } - recordCount++; - - if (recordCount >= segmentSize * numSegments) { - break; - } - } - } catch (IdleReaderException exc) { - exceptionEncountered = true; - } - assertTrue(!exceptionEncountered); - Assert.assertEquals(recordCount, segmentSize * numSegments); - assertTrue(!currentThread.isInterrupted()); - Utils.close(reader); - executor.shutdown(); - } - - @Test(timeout = 60000) - public void testGetLastTxId() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - - int numRecords = 10; - for (int i = 0; i < numRecords; i++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(i))); - assertEquals("last tx id should become " + i, - i, writer.getLastTxId()); - } - // open a writer to recover the inprogress log segment - AsyncLogWriter recoverWriter = dlm.startAsyncLogSegmentNonPartitioned(); - assertEquals("recovered last tx id should be " + (numRecords - 1), - numRecords - 1, recoverWriter.getLastTxId()); - } - - @Test(timeout = 60000) - public void testMaxReadAheadRecords() throws Exception { - int maxRecords = 1; - int batchSize = 8; - int maxAllowedCachedRecords = maxRecords + batchSize - 1; - - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setPeriodicFlushFrequencyMilliSeconds(Integer.MAX_VALUE); - confLocal.setReadAheadMaxRecords(maxRecords); - confLocal.setReadAheadBatchSize(batchSize); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - - int numRecords = 40; - for (int i = 1; i <= numRecords; i++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(i))); - assertEquals("last tx id should become " + i, - i, writer.getLastTxId()); - } - LogRecord record = DLMTestUtil.getLogRecordInstance(numRecords); - record.setControl(); - Utils.ioResult(writer.write(record)); - - BKAsyncLogReader reader = (BKAsyncLogReader) dlm.getAsyncLogReader(DLSN.InitialDLSN); - record = Utils.ioResult(reader.readNext()); - LOG.info("Read record {}", record); - assertEquals(1L, record.getTransactionId()); - - assertNotNull(reader.getReadAheadReader()); - assertTrue(reader.getReadAheadReader().getNumCachedEntries() <= maxAllowedCachedRecords); - - for (int i = 2; i <= numRecords; i++) { - record = Utils.ioResult(reader.readNext()); - LOG.info("Read record {}", record); - assertEquals((long) i, record.getTransactionId()); - TimeUnit.MILLISECONDS.sleep(20); - int numCachedEntries = reader.getReadAheadReader().getNumCachedEntries(); - assertTrue("Should cache less than " + batchSize + " records but already found " - + numCachedEntries + " records when reading " + i + "th record", - numCachedEntries <= maxAllowedCachedRecords); - } - Utils.close(reader); - } - - @Test(timeout = 60000) - public void testMarkEndOfStream() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - - final int numRecords = 10; - int i = 1; - for (; i <= numRecords; i++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(i))); - assertEquals("last tx id should become " + i, - i, writer.getLastTxId()); - } - - Utils.ioResult(writer.markEndOfStream()); - - // Multiple end of streams are ok. - Utils.ioResult(writer.markEndOfStream()); - - try { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(i))); - fail("Should have thrown"); - } catch (EndOfStreamException ex) { - } - - BKAsyncLogReader reader = (BKAsyncLogReader) dlm.getAsyncLogReader(DLSN.InitialDLSN); - LogRecord record = null; - for (int j = 0; j < numRecords; j++) { - record = Utils.ioResult(reader.readNext()); - assertEquals(j + 1, record.getTransactionId()); - } - - try { - record = Utils.ioResult(reader.readNext()); - fail("Should have thrown"); - } catch (EndOfStreamException ex) { - } - Utils.close(reader); - } - - @Test(timeout = 60000) - public void testMarkEndOfStreamAtBeginningOfSegment() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.markEndOfStream()); - try { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1))); - fail("Should have thrown"); - } catch (EndOfStreamException ex) { - } - writer.close(); - - BKAsyncLogReader reader = (BKAsyncLogReader) dlm.getAsyncLogReader(DLSN.InitialDLSN); - try { - LogRecord record = Utils.ioResult(reader.readNext()); - fail("Should have thrown"); - } catch (EndOfStreamException ex) { - } - Utils.close(reader); - } - - @Test(timeout = 60000) - public void testBulkReadWaitingMoreRecords() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - LogRecord controlRecord = DLMTestUtil.getLogRecordInstance(1L); - controlRecord.setControl(); - Utils.ioResult(writer.write(controlRecord)); - - BKAsyncLogReader reader = (BKAsyncLogReader) dlm.getAsyncLogReader(DLSN.InitialDLSN); - CompletableFuture> bulkReadFuture = - reader.readBulk(2, Long.MAX_VALUE, TimeUnit.MILLISECONDS); - CompletableFuture readFuture = reader.readNext(); - - // write another records - for (int i = 0; i < 5; i++) { - long txid = 2L + i; - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid))); - controlRecord = DLMTestUtil.getLogRecordInstance(txid); - controlRecord.setControl(); - Utils.ioResult(writer.write(controlRecord)); - } - - List bulkReadRecords = Utils.ioResult(bulkReadFuture); - assertEquals(2, bulkReadRecords.size()); - assertEquals(1L, bulkReadRecords.get(0).getTransactionId()); - assertEquals(2L, bulkReadRecords.get(1).getTransactionId()); - for (LogRecordWithDLSN record : bulkReadRecords) { - DLMTestUtil.verifyLogRecord(record); - } - LogRecordWithDLSN record = Utils.ioResult(readFuture); - assertEquals(3L, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - - Utils.close(reader); - writer.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testBulkReadNotWaitingMoreRecords() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - LogRecord controlRecord = DLMTestUtil.getLogRecordInstance(1L); - controlRecord.setControl(); - Utils.ioResult(writer.write(controlRecord)); - - BKAsyncLogReader reader = (BKAsyncLogReader) dlm.getAsyncLogReader(DLSN.InitialDLSN); - CompletableFuture> bulkReadFuture = reader.readBulk(2, 0, TimeUnit.MILLISECONDS); - CompletableFuture readFuture = reader.readNext(); - - List bulkReadRecords = Utils.ioResult(bulkReadFuture); - assertEquals(1, bulkReadRecords.size()); - assertEquals(1L, bulkReadRecords.get(0).getTransactionId()); - for (LogRecordWithDLSN record : bulkReadRecords) { - DLMTestUtil.verifyLogRecord(record); - } - - // write another records - for (int i = 0; i < 5; i++) { - long txid = 2L + i; - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid))); - controlRecord = DLMTestUtil.getLogRecordInstance(txid); - controlRecord.setControl(); - Utils.ioResult(writer.write(controlRecord)); - } - - LogRecordWithDLSN record = Utils.ioResult(readFuture); - assertEquals(2L, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - - Utils.close(reader); - writer.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReadBrokenEntries() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(1); - confLocal.setPositionGapDetectionEnabled(false); - confLocal.setReadAheadSkipBrokenEntries(true); - confLocal.setEIInjectReadAheadBrokenEntries(true); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 10; - - long txid = 1L; - txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, false); - - AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - - // 3 segments, 10 records each, immediate flush, batch size 1, so just the first - // record in each ledger is discarded, for 30 - 3 = 27 records. - for (int i = 0; i < 27; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertFalse(record.getDlsn().getEntryId() % 10 == 0); - } - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReadBrokenEntriesWithGapDetection() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(1); - confLocal.setPositionGapDetectionEnabled(true); - confLocal.setReadAheadSkipBrokenEntries(true); - confLocal.setEIInjectReadAheadBrokenEntries(true); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 1; - int numRecordsPerLogSegment = 100; - - long txid = 1L; - txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, false); - - AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - - try { - // 3 segments, 10 records each, immediate flush, batch size 1, so just the first - // record in each ledger is discarded, for 30 - 3 = 27 records. - for (int i = 0; i < 30; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertFalse(record.getDlsn().getEntryId() % 10 == 0); - } - fail("should have thrown"); - } catch (DLIllegalStateException e) { - } - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReadBrokenEntriesAndLargeBatchSize() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(5); - confLocal.setPositionGapDetectionEnabled(false); - confLocal.setReadAheadSkipBrokenEntries(true); - confLocal.setEIInjectReadAheadBrokenEntries(true); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 1; - int numRecordsPerLogSegment = 100; - - long txid = 1L; - txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, false); - - AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - - // Every 10th record broken. Reading 5 at once, beginning from 0: - // 1. range 0-4 will be corrupted and discarded - // 2. ranges 1-5, 2-6, 3-7, 4-8, 5-9 will be ok - // 3. ranges 6-10, 7-11, 8-12, 9-13 will be bad - // And so on, so 5 records in each 10 will be discarded, for 50 good records. - for (int i = 0; i < 50; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertFalse(record.getDlsn().getEntryId() % 10 == 0); - } - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReadBrokenEntriesAndLargeBatchSizeCrossSegment() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(testConf); - - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(true); - confLocal.setReadAheadWaitTime(10); - confLocal.setReadAheadBatchSize(8); - confLocal.setPositionGapDetectionEnabled(false); - confLocal.setReadAheadSkipBrokenEntries(true); - confLocal.setEIInjectReadAheadBrokenEntries(true); - DistributedLogManager dlm = createNewDLM(confLocal, name); - - int numLogSegments = 3; - int numRecordsPerLogSegment = 5; - - long txid = 1L; - txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, false); - - AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - - // Every 10th record broken. Reading 8 at once, beginning from 0: - // 1. range 0-7 will be corrupted and discarded - // 2. range 1-8 will be good, but only contain 4 records - // And so on for the next segment, so 4 records in each segment, for 12 good records - for (int i = 0; i < 12; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertFalse(record.getDlsn().getEntryId() % 10 == 0); - } - - Utils.close(reader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testCreateLogStreamWithDifferentReplicationFactor() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - - ConcurrentBaseConfiguration baseConf = new ConcurrentConstConfiguration(confLocal); - DynamicDistributedLogConfiguration dynConf = new DynamicDistributedLogConfiguration(baseConf); - dynConf.setProperty(DistributedLogConfiguration.BKDL_BOOKKEEPER_ENSEMBLE_SIZE, - DistributedLogConfiguration.BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT - 1); - - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(confLocal).uri(uri).build(); - - // use the pool - DistributedLogManager dlm = namespace.openLog(name + "-pool"); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - List segments = dlm.getLogSegments(); - assertEquals(1, segments.size()); - long ledgerId = segments.get(0).getLogSegmentId(); - LedgerHandle lh = ((BKNamespaceDriver) namespace.getNamespaceDriver()).getReaderBKC().get() - .openLedgerNoRecovery(ledgerId, BookKeeper.DigestType.CRC32, confLocal.getBKDigestPW().getBytes(UTF_8)); - LedgerMetadata metadata = lh.getLedgerMetadata(); - assertEquals(DistributedLogConfiguration.BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT, metadata.getEnsembleSize()); - lh.close(); - Utils.close(writer); - dlm.close(); - - // use customized configuration - dlm = namespace.openLog( - name + "-custom", - java.util.Optional.empty(), - java.util.Optional.of(dynConf), - java.util.Optional.empty()); - writer = dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - segments = dlm.getLogSegments(); - assertEquals(1, segments.size()); - ledgerId = segments.get(0).getLogSegmentId(); - lh = ((BKNamespaceDriver) namespace.getNamespaceDriver()).getReaderBKC().get() - .openLedgerNoRecovery(ledgerId, BookKeeper.DigestType.CRC32, confLocal.getBKDigestPW().getBytes(UTF_8)); - metadata = lh.getLedgerMetadata(); - assertEquals(DistributedLogConfiguration.BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT - 1, metadata.getEnsembleSize()); - lh.close(); - Utils.close(writer); - dlm.close(); - namespace.close(); - } - - @Test(timeout = 60000) - public void testWriteRecordSet() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - List> writeFutures = Lists.newArrayList(); - for (int i = 0; i < 5; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(1L + i); - writeFutures.add(writer.write(record)); - } - List> recordSetFutures = Lists.newArrayList(); - // write another 5 records - final LogRecordSet.Writer recordSetWriter = LogRecordSet.newWriter(4096, CompressionCodec.Type.LZ4); - for (int i = 0; i < 5; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(6L + i); - CompletableFuture writePromise = new CompletableFuture(); - recordSetWriter.writeRecord(ByteBuffer.wrap(record.getPayload()), writePromise); - recordSetFutures.add(writePromise); - } - final ByteBuf recordSetBuffer = recordSetWriter.getBuffer(); - LogRecord setRecord = new LogRecord(6L, recordSetBuffer); - setRecord.setRecordSet(); - CompletableFuture writeRecordSetFuture = writer.write(setRecord); - writeRecordSetFuture.whenComplete(new FutureEventListener() { - @Override - public void onSuccess(DLSN dlsn) { - recordSetWriter.completeTransmit( - dlsn.getLogSegmentSequenceNo(), - dlsn.getEntryId(), - dlsn.getSlotId()); - } - - @Override - public void onFailure(Throwable cause) { - recordSetWriter.abortTransmit(cause); - } - }); - writeFutures.add(writeRecordSetFuture); - Utils.ioResult(writeRecordSetFuture); - // write last 5 records - for (int i = 0; i < 5; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(11L + i); - CompletableFuture writeFuture = writer.write(record); - writeFutures.add(writeFuture); - // make sure get log record count returns the right count - if (i == 0) { - Utils.ioResult(writeFuture); - assertEquals(10, dlm.getLogRecordCount()); - } - } - - List writeResults = Utils.ioResult(FutureUtils.collect(writeFutures)); - - for (int i = 0; i < 5; i++) { - Assert.assertEquals(new DLSN(1L, i, 0L), writeResults.get(i)); - } - Assert.assertEquals(new DLSN(1L, 5L, 0L), writeResults.get(5)); - for (int i = 0; i < 5; i++) { - Assert.assertEquals(new DLSN(1L, 6L + i, 0L), writeResults.get(6 + i)); - } - List recordSetWriteResults = Utils.ioResult(FutureUtils.collect(recordSetFutures)); - for (int i = 0; i < 5; i++) { - Assert.assertEquals(new DLSN(1L, 5L, i), recordSetWriteResults.get(i)); - } - - Utils.ioResult(writer.flushAndCommit()); - - DistributedLogConfiguration readConf1 = new DistributedLogConfiguration(); - readConf1.addConfiguration(confLocal); - readConf1.setDeserializeRecordSetOnReads(true); - - DistributedLogManager readDLM1 = createNewDLM(readConf1, name); - AsyncLogReader reader1 = readDLM1.getAsyncLogReader(DLSN.InitialDLSN); - for (int i = 0; i < 15; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader1.readNext()); - if (i < 5) { - assertEquals(new DLSN(1L, i, 0L), record.getDlsn()); - assertEquals(1L + i, record.getTransactionId()); - } else if (i >= 10) { - assertEquals(new DLSN(1L, 6L + i - 10, 0L), record.getDlsn()); - assertEquals(11L + i - 10, record.getTransactionId()); - } else { - assertEquals(new DLSN(1L, 5L, i - 5), record.getDlsn()); - assertEquals(6L, record.getTransactionId()); - } - assertEquals(i + 1, record.getPositionWithinLogSegment()); - assertArrayEquals(DLMTestUtil.generatePayload(i + 1), record.getPayload()); - } - Utils.close(reader1); - readDLM1.close(); - - DistributedLogConfiguration readConf2 = new DistributedLogConfiguration(); - readConf2.addConfiguration(confLocal); - readConf2.setDeserializeRecordSetOnReads(false); - - DistributedLogManager readDLM2 = createNewDLM(readConf2, name); - AsyncLogReader reader2 = readDLM2.getAsyncLogReader(DLSN.InitialDLSN); - for (int i = 0; i < 11; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader2.readNext()); - LOG.info("Read record {}", record); - if (i < 5) { - assertEquals(new DLSN(1L, i, 0L), record.getDlsn()); - assertEquals(1L + i, record.getTransactionId()); - assertEquals(i + 1, record.getPositionWithinLogSegment()); - assertArrayEquals(DLMTestUtil.generatePayload(i + 1), record.getPayload()); - } else if (i >= 6L) { - assertEquals(new DLSN(1L, 6L + i - 6, 0L), record.getDlsn()); - assertEquals(11L + i - 6, record.getTransactionId()); - assertEquals(11 + i - 6, record.getPositionWithinLogSegment()); - assertArrayEquals(DLMTestUtil.generatePayload(11L + i - 6), record.getPayload()); - } else { - assertEquals(new DLSN(1L, 5L, 0), record.getDlsn()); - assertEquals(6L, record.getTransactionId()); - assertEquals(6, record.getPositionWithinLogSegment()); - assertTrue(record.isRecordSet()); - assertEquals(5, LogRecordSet.numRecords(record)); - } - } - Utils.close(reader2); - readDLM2.close(); - } - - @Test(timeout = 60000) - public void testIdleReaderExceptionWhenKeepAliveIsDisabled() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setPeriodicKeepAliveMilliSeconds(0); - confLocal.setReadLACLongPollTimeout(9); - confLocal.setReaderIdleWarnThresholdMillis(20); - confLocal.setReaderIdleErrorThresholdMillis(40); - - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) Utils.ioResult(dlm.openAsyncLogWriter()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - - AsyncLogReader reader = Utils.ioResult(dlm.openAsyncLogReader(DLSN.InitialDLSN)); - try { - Utils.ioResult(reader.readNext()); - fail("Should fail when stream is idle"); - } catch (IdleReaderException ire) { - // expected - } - Utils.close(reader); - writer.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testIdleReaderExceptionWhenKeepAliveIsEnabled() throws Exception { - String name = runtime.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(testConf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setPeriodicKeepAliveMilliSeconds(1000); - confLocal.setReadLACLongPollTimeout(999); - confLocal.setReaderIdleWarnThresholdMillis(2000); - confLocal.setReaderIdleErrorThresholdMillis(4000); - - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) Utils.ioResult(dlm.openAsyncLogWriter()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - - AsyncLogReader reader = Utils.ioResult(dlm.openAsyncLogReader(DLSN.InitialDLSN)); - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertEquals(1L, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - - Utils.close(reader); - writer.close(); - dlm.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogManager.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogManager.java deleted file mode 100644 index e26667dd04f..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogManager.java +++ /dev/null @@ -1,1413 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.api.LogWriter; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.api.subscription.SubscriptionsStore; -import org.apache.distributedlog.bk.LedgerMetadata; -import org.apache.distributedlog.callback.LogSegmentListener; -import org.apache.distributedlog.exceptions.AlreadyTruncatedTransactionException; -import org.apache.distributedlog.exceptions.BKTransmitException; -import org.apache.distributedlog.exceptions.DLIllegalStateException; -import org.apache.distributedlog.exceptions.EndOfStreamException; -import org.apache.distributedlog.exceptions.InvalidStreamNameException; -import org.apache.distributedlog.exceptions.LogEmptyException; -import org.apache.distributedlog.exceptions.LogNotFoundException; -import org.apache.distributedlog.exceptions.LogReadException; -import org.apache.distributedlog.exceptions.LogRecordTooLongException; -import org.apache.distributedlog.exceptions.TransactionIdOutOfOrderException; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.impl.ZKLogSegmentMetadataStore; -import org.apache.distributedlog.io.Abortables; -import org.apache.distributedlog.logsegment.LogSegmentMetadataStore; -import org.apache.distributedlog.metadata.LogMetadata; -import org.apache.distributedlog.metadata.LogSegmentMetadataStoreUpdater; -import org.apache.distributedlog.metadata.MetadataUpdater; -import org.apache.distributedlog.util.Utils; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for {@link DistributedLogManager}. - */ -@Slf4j -public class TestBKDistributedLogManager extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestBKDistributedLogManager.class); - - private static final Random RAND = new Random(System.currentTimeMillis()); - - protected static int numBookies = 1; - static { - conf.setEnsembleSize(numBookies) - .setAckQuorumSize(numBookies) - .setWriteQuorumSize(numBookies); - } - - @Rule - public TestName testNames = new TestName(); - - private static final long DEFAULT_SEGMENT_SIZE = 1000; - - @BeforeClass - public static void setupCluster() throws Exception { - setupCluster(numBookies); - } - - /** - * Test that DLM can reliably read data. - * Write multiple segments, read back multiple times. - * Make sure all entries from all segments are read back. - */ - @Test(timeout = 120000) - public void testReadMultipleSegments() throws Exception { - String name = "distrlog-testReadMultipleSegments"; - - final int numSegments = 10; - final int numEntriesPerSegment = 2; - final int numReadIterations = 10; - - BKDistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - for (long i = 0; i < numSegments; i++) { - BKSyncLogWriter out = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= numEntriesPerSegment; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.closeAndComplete(); - out = dlm.startLogSegmentNonPartitioned(); - out.closeAndComplete(); - } - assertEquals(txid - 1, dlm.getLastTxId()); - dlm.close(); - - for (int runId = 0; runId < numReadIterations; runId++) { - dlm = createNewDLM(conf, name); - assertEquals(txid - 1, dlm.getLastTxId()); - - long numLogRecs = 0; - LogReader reader = dlm.getInputStream(1); - LogRecord record = reader.readNext(false); - while (null != record) { - numLogRecs++; - DLMTestUtil.verifyLogRecord(record); - assertEquals("(skipped txs in the middle) Failed at iteration " + runId, - numLogRecs, record.getTransactionId()); - record = reader.readNext(false); - } - reader.close(); - dlm.close(); - - assertEquals("(missed txs at the end) Failed at iteration " + runId, - txid - 1, numLogRecs); - } - } - - private void testNonPartitionedWritesInternal(String name, DistributedLogConfiguration conf) throws Exception { - BKDistributedLogManager dlm = createNewDLM(conf, name); - - long txid = 1; - for (long i = 0; i < 3; i++) { - long start = txid; - BKSyncLogWriter writer = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - BKLogSegmentWriter perStreamLogWriter = writer.getCachedLogWriter(); - writer.closeAndComplete(); - BKLogWriteHandler blplm = dlm.createWriteHandler(true); - assertNotNull(zkc.exists(blplm.completedLedgerZNode(start, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } - - LogWriter writer = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE / 2; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - writer.flush(); - writer.commit(); - writer.close(); - assertEquals(txid - 1, dlm.getLastTxId()); - - LogReader reader = dlm.getInputStream(1); - long numTrans = 0; - LogRecord record = reader.readNext(false); - long lastTxId = -1; - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - assert (lastTxId < record.getTransactionId()); - lastTxId = record.getTransactionId(); - numTrans++; - record = reader.readNext(false); - } - reader.close(); - assertEquals((txid - 1), numTrans); - dlm.close(); - } - - @Test(timeout = 60000) - public void testSimpleWrite() throws Exception { - BKDistributedLogManager dlm = createNewDLM(conf, "distrlog-simplewrite"); - BKSyncLogWriter out = dlm.startLogSegmentNonPartitioned(); - for (long i = 1; i <= 100; i++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(i); - out.write(op); - } - BKLogSegmentWriter perStreamLogWriter = out.getCachedLogWriter(); - out.closeAndComplete(); - - BKLogWriteHandler blplm = dlm.createWriteHandler(true); - assertNotNull(zkc.exists(blplm.completedLedgerZNode(1, 100, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - dlm.close(); - } - - @Test(timeout = 60000) - public void testNumberOfTransactions() throws Exception { - String name = "distrlog-txncount"; - DistributedLogManager dlm = createNewDLM(conf, name); - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 1; i <= 100; i++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(i); - out.write(op); - } - out.closeAndComplete(); - - dlm.close(); - dlm = createNewDLM(conf, name); - - long numTrans = DLMTestUtil.getNumberofLogRecords(dlm, 1); - assertEquals(100, numTrans); - dlm.close(); - } - - @Test(timeout = 60000) - public void testContinuousReaders() throws Exception { - String name = "distrlog-continuous"; - BKDistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - for (long i = 0; i < 3; i++) { - long start = txid; - BKSyncLogWriter out = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - BKLogSegmentWriter perStreamLogWriter = out.getCachedLogWriter(); - out.closeAndComplete(); - BKLogWriteHandler blplm = dlm.createWriteHandler(true); - - assertNotNull( - zkc.exists(blplm.completedLedgerZNode(start, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } - - BKSyncLogWriter out = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE / 2; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.flush(); - out.commit(); - out.close(); - - assertEquals(txid - 1, dlm.getLastTxId()); - dlm.close(); - - dlm = createNewDLM(conf, name); - - LogReader reader = dlm.getInputStream(1); - long numTrans = 0; - LogRecord record = reader.readNext(false); - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - numTrans++; - record = reader.readNext(false); - } - assertEquals((txid - 1), numTrans); - assertEquals(txid - 1, dlm.getLogRecordCount()); - reader.close(); - dlm.close(); - } - - /** - * Create a bkdlm namespace, write a journal from txid 1, close stream. - * Try to create a new journal from txid 1. Should throw an exception. - */ - @Test(timeout = 60000) - public void testWriteRestartFrom1() throws Exception { - DistributedLogManager dlm = createNewDLM(conf, "distrlog-restartFrom1"); - long txid = 1; - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.closeAndComplete(); - - txid = 1; - try { - out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - out.write(DLMTestUtil.getLogRecordInstance(txid)); - fail("Shouldn't be able to start another journal from " + txid - + " when one already exists"); - } catch (Exception ioe) { - LOG.info("Caught exception as expected", ioe); - } finally { - out.close(); - } - - // test border case - txid = DEFAULT_SEGMENT_SIZE - 1; - try { - out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - out.write(DLMTestUtil.getLogRecordInstance(txid)); - fail("Shouldn't be able to start another journal from " + txid - + " when one already exists"); - } catch (TransactionIdOutOfOrderException rste) { - LOG.info("Caught exception as expected", rste); - } finally { - out.close(); - } - - // open journal continuing from before - txid = DEFAULT_SEGMENT_SIZE + 1; - out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - assertNotNull(out); - - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.closeAndComplete(); - - // open journal arbitarily far in the future - txid = DEFAULT_SEGMENT_SIZE * 4; - out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - out.write(DLMTestUtil.getLogRecordInstance(txid)); - out.close(); - dlm.close(); - } - - @Test(timeout = 90000) - public void testTwoWritersOnLockDisabled() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setWriteLockEnabled(false); - String name = "distrlog-two-writers-lock-disabled"; - BKDistributedLogManager manager = createNewDLM(confLocal, name); - AsyncLogWriter writer1 = Utils.ioResult(manager.openAsyncLogWriter()); - Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(1L))); - Assert.assertEquals(1L, writer1.getLastTxId()); - // some flaky ZK errors, Issue 3063 - Thread.sleep(1000); - AsyncLogWriter writer2 = Utils.ioResult(manager.openAsyncLogWriter()); - Utils.ioResult(writer2.write(DLMTestUtil.getLogRecordInstance(2L))); - Assert.assertEquals(2L, writer2.getLastTxId()); - - // write a record to writer 1 again - try { - Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(3L))); - fail("Should fail writing record to writer 1 again as writer 2 took over the ownership"); - } catch (BKTransmitException bkte) { - assertEquals(BKException.Code.LedgerFencedException, bkte.getBKResultCode()); - } - Utils.ioResult(writer1.asyncClose()); - Utils.ioResult(writer2.asyncClose()); - manager.close(); - } - - @Test(timeout = 60000) - public void testSimpleRead() throws Exception { - String name = "distrlog-simpleread"; - DistributedLogManager dlm = createNewDLM(conf, name); - final long numTransactions = 10000; - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 1; i <= numTransactions; i++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(i); - out.write(op); - } - out.closeAndComplete(); - dlm.close(); - - dlm = createNewDLM(conf, name); - - assertEquals(numTransactions, DLMTestUtil.getNumberofLogRecords(dlm, 1)); - dlm.close(); - } - - @Test(timeout = 60000) - public void testNumberOfTransactionsWithInprogressAtEnd() throws Exception { - String name = "distrlog-inprogressAtEnd"; - DistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - for (long i = 0; i < 3; i++) { - long start = txid; - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - BKLogSegmentWriter perStreamLogWriter = out.getCachedLogWriter(); - out.closeAndComplete(); - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - assertNotNull( - zkc.exists(blplm.completedLedgerZNode(start, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE / 2; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.flush(); - out.commit(); - out.closeAndComplete(); - - assertEquals(txid - 1, dlm.getLastTxId()); - dlm.close(); - - dlm = createNewDLM(conf, name); - - long numTrans = DLMTestUtil.getNumberofLogRecords(dlm, 1); - assertEquals((txid - 1), numTrans); - dlm.close(); - } - - @Test(timeout = 60000) - public void testContinuousReaderBulk() throws Exception { - String name = "distrlog-continuous-bulk"; - DistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - for (long i = 0; i < 3; i++) { - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.flush(); - out.commit(); - out.closeAndComplete(); - } - - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE / 2; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.flush(); - out.commit(); - out.closeAndComplete(); - assertEquals(txid - 1, dlm.getLastTxId()); - dlm.close(); - - dlm = createNewDLM(conf, name); - - LogReader reader = dlm.getInputStream(1); - long numTrans = 0; - List recordList = reader.readBulk(false, 13); - long lastTxId = -1; - while (!recordList.isEmpty()) { - for (LogRecord record : recordList) { - assert (lastTxId < record.getTransactionId()); - lastTxId = record.getTransactionId(); - DLMTestUtil.verifyLogRecord(record); - numTrans++; - } - recordList = reader.readBulk(false, 13); - } - reader.close(); - assertEquals((txid - 1), numTrans); - dlm.close(); - } - - @Test(timeout = 60000) - public void testContinuousReadersWithEmptyLedgers() throws Exception { - String name = "distrlog-continuous-emptyledgers"; - DistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - for (long i = 0; i < 3; i++) { - long start = txid; - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - BKLogSegmentWriter writer = out.getCachedLogWriter(); - out.closeAndComplete(); - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - - assertNotNull( - zkc.exists(blplm.completedLedgerZNode(start, txid - 1, - writer.getLogSegmentSequenceNumber()), false)); - BKLogSegmentWriter perStreamLogWriter = blplm.startLogSegment(txid - 1); - blplm.completeAndCloseLogSegment(perStreamLogWriter.getLogSegmentSequenceNumber(), - perStreamLogWriter.getLogSegmentId(), txid - 1, txid - 1, 0); - assertNotNull( - zkc.exists(blplm.completedLedgerZNode(txid - 1, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } - - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE / 2; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.flush(); - out.commit(); - out.closeAndComplete(); - assertEquals(txid - 1, dlm.getLastTxId()); - dlm.close(); - - dlm = createNewDLM(conf, name); - - AsyncLogReader asyncreader = dlm.getAsyncLogReader(DLSN.InvalidDLSN); - long numTrans = 0; - LogRecordWithDLSN record = Utils.ioResult(asyncreader.readNext()); - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - numTrans++; - if (numTrans >= (txid - 1)) { - break; - } - record = Utils.ioResult(asyncreader.readNext()); - } - assertEquals((txid - 1), numTrans); - Utils.close(asyncreader); - - LogReader reader = dlm.getInputStream(1); - numTrans = 0; - record = reader.readNext(false); - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - numTrans++; - record = reader.readNext(false); - } - assertEquals((txid - 1), numTrans); - reader.close(); - assertEquals(txid - 1, dlm.getLogRecordCount()); - dlm.close(); - } - - @Test(timeout = 60000) - public void testNonPartitionedWrites() throws Exception { - String name = "distrlog-non-partitioned-bulk"; - testNonPartitionedWritesInternal(name, conf); - } - - @Test(timeout = 60000) - public void testCheckLogExists() throws Exception { - String name = "distrlog-check-log-exists"; - DistributedLogManager dlm = createNewDLM(conf, name); - - long txid = 1; - LogWriter writer = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE / 2; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - writer.flush(); - writer.commit(); - writer.close(); - assertEquals(txid - 1, dlm.getLastTxId()); - dlm.close(); - - URI uri = createDLMURI("/" + name); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf).uri(uri).build(); - assertTrue(namespace.logExists(name)); - assertFalse(namespace.logExists("non-existent-log")); - URI nonExistentUri = createDLMURI("/" + "non-existent-ns"); - Namespace nonExistentNS = NamespaceBuilder.newBuilder() - .conf(conf).uri(nonExistentUri).build(); - assertFalse(nonExistentNS.logExists(name)); - - int logCount = 0; - Iterator logIter = namespace.getLogs(); - while (logIter.hasNext()) { - String log = logIter.next(); - logCount++; - assertEquals(name, log); - } - assertEquals(1, logCount); - - namespace.close(); - } - - @SuppressWarnings("deprecation") - @Test(timeout = 60000) - public void testMetadataAccessor() throws Exception { - String name = "distrlog-metadata-accessor"; - org.apache.distributedlog.api.MetadataAccessor metadata = - DLMTestUtil.createNewMetadataAccessor(conf, name, createDLMURI("/" + name)); - assertEquals(name, metadata.getStreamName()); - metadata.createOrUpdateMetadata(name.getBytes()); - assertEquals(name, new String(metadata.getMetadata())); - metadata.deleteMetadata(); - assertEquals(null, metadata.getMetadata()); - } - - @Test(timeout = 60000) - public void testSubscriptionsStore() throws Exception { - String name = "distrlog-subscriptions-store"; - String subscriber0 = "subscriber-0"; - String subscriber1 = "subscriber-1"; - String subscriber2 = "subscriber-2"; - - DLSN commitPosition0 = new DLSN(4, 33, 5); - DLSN commitPosition1 = new DLSN(4, 34, 5); - DLSN commitPosition2 = new DLSN(5, 34, 5); - DLSN commitPosition3 = new DLSN(6, 35, 6); - - DistributedLogManager dlm = createNewDLM(conf, name); - - SubscriptionsStore store = dlm.getSubscriptionsStore(); - - // no data - assertEquals(Utils.ioResult(store.getLastCommitPosition(subscriber0)), DLSN.NonInclusiveLowerBound); - assertEquals(Utils.ioResult(store.getLastCommitPosition(subscriber1)), DLSN.NonInclusiveLowerBound); - assertEquals(Utils.ioResult(store.getLastCommitPosition(subscriber2)), DLSN.NonInclusiveLowerBound); - // empty - assertTrue(Utils.ioResult(store.getLastCommitPositions()).isEmpty()); - - // subscriber 0 advance - Utils.ioResult(store.advanceCommitPosition(subscriber0, commitPosition0)); - assertEquals(commitPosition0, Utils.ioResult(store.getLastCommitPosition(subscriber0))); - Map committedPositions = Utils.ioResult(store.getLastCommitPositions()); - assertEquals(1, committedPositions.size()); - assertEquals(commitPosition0, committedPositions.get(subscriber0)); - - // subscriber 1 advance - Utils.ioResult(store.advanceCommitPosition(subscriber1, commitPosition1)); - assertEquals(commitPosition1, Utils.ioResult(store.getLastCommitPosition(subscriber1))); - committedPositions = Utils.ioResult(store.getLastCommitPositions()); - assertEquals(2, committedPositions.size()); - assertEquals(commitPosition0, committedPositions.get(subscriber0)); - assertEquals(commitPosition1, committedPositions.get(subscriber1)); - - // subscriber 2 advance - Utils.ioResult(store.advanceCommitPosition(subscriber2, commitPosition2)); - assertEquals(commitPosition2, Utils.ioResult(store.getLastCommitPosition(subscriber2))); - committedPositions = Utils.ioResult(store.getLastCommitPositions()); - assertEquals(3, committedPositions.size()); - assertEquals(commitPosition0, committedPositions.get(subscriber0)); - assertEquals(commitPosition1, committedPositions.get(subscriber1)); - assertEquals(commitPosition2, committedPositions.get(subscriber2)); - - // subscriber 2 advance again - DistributedLogManager newDLM = createNewDLM(conf, name); - SubscriptionsStore newStore = newDLM.getSubscriptionsStore(); - Utils.ioResult(newStore.advanceCommitPosition(subscriber2, commitPosition3)); - newStore.close(); - newDLM.close(); - - committedPositions = Utils.ioResult(store.getLastCommitPositions()); - assertEquals(3, committedPositions.size()); - assertEquals(commitPosition0, committedPositions.get(subscriber0)); - assertEquals(commitPosition1, committedPositions.get(subscriber1)); - assertEquals(commitPosition3, committedPositions.get(subscriber2)); - - dlm.close(); - - } - - private long writeAndMarkEndOfStream(DistributedLogManager dlm, long txid) throws Exception { - for (long i = 0; i < 3; i++) { - long start = txid; - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - - BKLogSegmentWriter perStreamLogWriter = writer.getCachedLogWriter(); - - if (i < 2) { - writer.closeAndComplete(); - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - assertNotNull(zkc.exists(blplm.completedLedgerZNode(start, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } else { - writer.markEndOfStream(); - writer.closeAndComplete(); - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - assertNotNull(zkc.exists(blplm.completedLedgerZNode(start, DistributedLogConstants.MAX_TXID, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } - ((BKDistributedLogManager) dlm).getScheduler().submit(() -> {}).get(); - } - return txid; - } - - @Test(timeout = 60000) - public void testMarkEndOfStream() throws Exception { - String name = "distrlog-mark-end-of-stream"; - DistributedLogManager dlm = createNewDLM(conf, name); - - long txid = 1; - txid = writeAndMarkEndOfStream(dlm, txid); - - LogReader reader = dlm.getInputStream(1); - long numTrans = 0; - boolean exceptionEncountered = false; - LogRecord record = null; - try { - record = reader.readNext(false); - long expectedTxId = 1; - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(expectedTxId, record.getTransactionId()); - expectedTxId++; - numTrans++; - record = reader.readNext(false); - } - } catch (EndOfStreamException exc) { - LOG.info("Encountered EndOfStream on reading records after {}", record); - exceptionEncountered = true; - } - assertEquals((txid - 1), numTrans); - assertTrue(exceptionEncountered); - exceptionEncountered = false; - try { - reader.readNext(false); - } catch (EndOfStreamException exc) { - exceptionEncountered = true; - } - assertTrue(exceptionEncountered); - reader.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testWriteFailsAfterMarkEndOfStream() throws Exception { - String name = "distrlog-mark-end-failure"; - DistributedLogManager dlm = createNewDLM(conf, name); - - long txid = 1; - txid = writeAndMarkEndOfStream(dlm, txid); - - assertEquals(txid - 1, dlm.getLastTxId()); - LogRecord last = dlm.getLastLogRecord(); - assertEquals(txid - 1, last.getTransactionId()); - DLMTestUtil.verifyLogRecord(last); - assertTrue(dlm.isEndOfStreamMarked()); - - LogWriter writer = null; - boolean exceptionEncountered = false; - try { - writer = dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE / 2; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - } catch (EndOfStreamException exc) { - exceptionEncountered = true; - } - writer.close(); - assertTrue(exceptionEncountered); - dlm.close(); - } - - @Test(timeout = 60000) - public void testMarkEndOfStreamOnEmptyStream() throws Exception { - markEndOfStreamOnEmptyLogSegment(0); - } - - @Test(timeout = 60000) - public void testMarkEndOfStreamOnClosedStream() throws Exception { - markEndOfStreamOnEmptyLogSegment(3); - } - - private void markEndOfStreamOnEmptyLogSegment(int numCompletedSegments) throws Exception { - String name = "distrlog-mark-end-empty-" + numCompletedSegments; - - DistributedLogManager dlm = createNewDLM(conf, name); - DLMTestUtil.generateCompletedLogSegments(dlm, conf, numCompletedSegments, DEFAULT_SEGMENT_SIZE); - - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - writer.markEndOfStream(); - writer.closeAndComplete(); - - LogReader reader = dlm.getInputStream(1); - long numTrans = 0; - boolean exceptionEncountered = false; - try { - LogRecord record = reader.readNext(false); - long lastTxId = -1; - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - assert (lastTxId < record.getTransactionId()); - lastTxId = record.getTransactionId(); - numTrans++; - record = reader.readNext(false); - } - } catch (EndOfStreamException exc) { - exceptionEncountered = true; - } - assertEquals(numCompletedSegments * DEFAULT_SEGMENT_SIZE, numTrans); - assertTrue(exceptionEncountered); - exceptionEncountered = false; - try { - reader.readNext(false); - } catch (EndOfStreamException exc) { - exceptionEncountered = true; - } - assertTrue(exceptionEncountered); - reader.close(); - dlm.close(); - } - - @Test(timeout = 60000, expected = LogRecordTooLongException.class) - public void testMaxLogRecSize() throws Exception { - DistributedLogManager dlm = createNewDLM(conf, "distrlog-maxlogRecSize"); - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - Utils.ioResult(writer.write(new LogRecord(1L, DLMTestUtil.repeatString( - DLMTestUtil.repeatString("abcdefgh", 256), 512).getBytes()))); - dlm.close(); - } - - @Test(timeout = 60000) - public void testMaxTransmissionSize() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setOutputBufferSize(1024 * 1024); - BKDistributedLogManager dlm = - createNewDLM(confLocal, "distrlog-transmissionSize"); - AsyncLogWriter out = Utils.ioResult(dlm.openAsyncLogWriter()); - boolean exceptionEncountered = false; - byte[] largePayload = new byte[(LogRecord.MAX_LOGRECORDSET_SIZE / 2) + 2]; - RAND.nextBytes(largePayload); - try { - LogRecord op = new LogRecord(1L, largePayload); - CompletableFuture firstWriteFuture = out.write(op); - op = new LogRecord(2L, largePayload); - // the second write will flush the first one, since we reached the maximum transmission size. - out.write(op); - Utils.ioResult(firstWriteFuture); - } catch (LogRecordTooLongException exc) { - exceptionEncountered = true; - } finally { - Utils.ioResult(out.asyncClose()); - } - assertFalse(exceptionEncountered); - Abortables.abortQuietly(out); - dlm.close(); - } - - @Test(timeout = 60000) - public void deleteDuringRead() throws Exception { - String name = "distrlog-delete-with-reader"; - DistributedLogManager dlm = createNewDLM(conf, name); - - long txid = 1; - for (long i = 0; i < 3; i++) { - long start = txid; - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - - BKLogSegmentWriter perStreamLogWriter = writer.getCachedLogWriter(); - - writer.closeAndComplete(); - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - assertNotNull(zkc.exists(blplm.completedLedgerZNode(start, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } - - LogReader reader = dlm.getInputStream(1); - LogRecord record = reader.readNext(false); - assert (null != record); - DLMTestUtil.verifyLogRecord(record); - long lastTxId = record.getTransactionId(); - - dlm.delete(); - - boolean exceptionEncountered; - try { - record = reader.readNext(false); - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - assert (lastTxId < record.getTransactionId()); - lastTxId = record.getTransactionId(); - record = reader.readNext(false); - } - // make sure the exception is thrown from readahead - while (true) { - reader.readNext(false); - } - } catch (LogReadException | LogNotFoundException | DLIllegalStateException e) { - exceptionEncountered = true; - } - assertTrue(exceptionEncountered); - reader.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testImmediateFlush() throws Exception { - String name = "distrlog-immediate-flush"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setOutputBufferSize(0); - testNonPartitionedWritesInternal(name, confLocal); - } - - @Test(timeout = 60000) - public void testLastLogRecordWithEmptyLedgers() throws Exception { - String name = "distrlog-lastLogRec-emptyledgers"; - DistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - for (long i = 0; i < 3; i++) { - long start = txid; - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - BKLogSegmentWriter perStreamLogWriter = out.getCachedLogWriter(); - out.closeAndComplete(); - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - - assertNotNull( - zkc.exists(blplm.completedLedgerZNode(start, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - BKLogSegmentWriter writer = blplm.startLogSegment(txid - 1); - blplm.completeAndCloseLogSegment(writer.getLogSegmentSequenceNumber(), - writer.getLogSegmentId(), txid - 1, txid - 1, 0); - assertNotNull( - zkc.exists(blplm.completedLedgerZNode(txid - 1, txid - 1, - writer.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - } - - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - LogRecord op = DLMTestUtil.getLogRecordInstance(txid); - op.setControl(); - out.write(op); - out.flush(); - out.commit(); - out.abort(); - dlm.close(); - - dlm = createNewDLM(conf, name); - - assertEquals(txid - 1, dlm.getLastTxId()); - LogRecord last = dlm.getLastLogRecord(); - assertEquals(txid - 1, last.getTransactionId()); - DLMTestUtil.verifyLogRecord(last); - assertEquals(txid - 1, dlm.getLogRecordCount()); - - dlm.close(); - } - - @Test(timeout = 60000) - public void testLogSegmentListener() throws Exception { - String name = "distrlog-logsegment-listener"; - int numSegments = 3; - final CountDownLatch[] latches = new CountDownLatch[numSegments + 1]; - for (int i = 0; i < numSegments + 1; i++) { - latches[i] = new CountDownLatch(1); - } - - final AtomicInteger numFailures = new AtomicInteger(0); - final AtomicReference> receivedStreams = - new AtomicReference>(); - - BKDistributedLogManager dlm = createNewDLM(conf, name); - - Utils.ioResult(dlm.getWriterMetadataStore().getLog(dlm.getUri(), name, true, true)); - dlm.registerListener(new LogSegmentListener() { - @Override - public void onSegmentsUpdated(List segments) { - int updates = segments.size(); - boolean hasIncompletedLogSegments = false; - for (LogSegmentMetadata l : segments) { - if (l.isInProgress()) { - hasIncompletedLogSegments = true; - break; - } - } - if (hasIncompletedLogSegments) { - return; - } - if (updates >= 1) { - if (segments.get(segments.size() - 1).getLogSegmentSequenceNumber() != updates) { - numFailures.incrementAndGet(); - } - } - receivedStreams.set(segments); - latches[updates].countDown(); - } - - @Override - public void onLogStreamDeleted() { - // no-op - } - }); - long txid = 1; - for (int i = 0; i < numSegments; i++) { - LOG.info("Waiting for creating log segment {}.", i); - latches[i].await(); - LOG.info("Creating log segment {}.", i); - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - LOG.info("Created log segment {}.", i); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - out.write(op); - } - out.closeAndComplete(); - LOG.info("Completed log segment {}.", i); - } - latches[numSegments].await(); - assertEquals(0, numFailures.get()); - assertNotNull(receivedStreams.get()); - assertEquals(numSegments, receivedStreams.get().size()); - int seqno = 1; - for (LogSegmentMetadata m : receivedStreams.get()) { - assertEquals(seqno, m.getLogSegmentSequenceNumber()); - assertEquals((seqno - 1) * DEFAULT_SEGMENT_SIZE + 1, m.getFirstTxId()); - assertEquals(seqno * DEFAULT_SEGMENT_SIZE, m.getLastTxId()); - ++seqno; - } - - dlm.close(); - } - - @Test(timeout = 60000) - public void testGetLastDLSN() throws Exception { - String name = "distrlog-get-last-dlsn"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setFirstNumEntriesPerReadLastRecordScan(2); - confLocal.setMaxNumEntriesPerReadLastRecordScan(4); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - long txid = 1; - LOG.info("Writing 10 control records"); - for (int i = 0; i < 10; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(txid++); - record.setControl(); - Utils.ioResult(writer.writeControlRecord(record)); - } - LOG.info("10 control records are written"); - - try { - dlm.getLastDLSN(); - fail("Should fail on getting last dlsn from an empty log."); - } catch (LogEmptyException lee) { - // expected - } - - writer.closeAndComplete(); - LOG.info("Completed first log segment"); - - writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid++))); - LOG.info("Completed second log segment"); - - LOG.info("Writing another 10 control records"); - for (int i = 1; i < 10; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(txid++); - record.setControl(); - Utils.ioResult(writer.write(record)); - } - - assertEquals(new DLSN(2, 0, 0), dlm.getLastDLSN()); - - writer.closeAndComplete(); - LOG.info("Completed third log segment"); - - assertEquals(new DLSN(2, 0, 0), dlm.getLastDLSN()); - - writer.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountAsync() throws Exception { - DistributedLogManager dlm = createNewDLM(conf, testNames.getMethodName()); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - DLMTestUtil.generateCompletedLogSegments(dlm, conf, 2, 10); - - CompletableFuture futureCount = dlm.getLogRecordCountAsync(DLSN.InitialDLSN); - Long count = Utils.ioResult(futureCount, 2, TimeUnit.SECONDS); - assertEquals(20, count.longValue()); - - writer.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testInvalidStreamFromInvalidZkPath() throws Exception { - String baseName = testNames.getMethodName(); - String streamName = "\0blah"; - URI uri = createDLMURI("/" + baseName); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf).uri(uri).build(); - - DistributedLogManager dlm = null; - AsyncLogWriter writer = null; - try { - dlm = namespace.openLog(streamName); - writer = dlm.startAsyncLogSegmentNonPartitioned(); - fail("should have thrown"); - } catch (InvalidStreamNameException e) { - } finally { - if (null != writer) { - Utils.close(writer); - } - if (null != dlm) { - dlm.close(); - } - namespace.close(); - } - } - - @Test(timeout = 60000) - public void testTruncationValidation() throws Exception { - String name = "distrlog-truncation-validation"; - URI uri = createDLMURI("/" + name); - ZooKeeperClient zookeeperClient = TestZooKeeperClientBuilder.newBuilder() - .uri(uri) - .build(); - OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-truncation-validation") - .numThreads(1) - .build(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setDLLedgerMetadataLayoutVersion(LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - confLocal.setOutputBufferSize(0); - confLocal.setLogSegmentCacheEnabled(false); - - LogSegmentMetadataStore metadataStore = new ZKLogSegmentMetadataStore(confLocal, zookeeperClient, scheduler); - - BKDistributedLogManager dlm = createNewDLM(confLocal, name); - DLSN truncDLSN = DLSN.InitialDLSN; - DLSN beyondTruncDLSN = DLSN.InitialDLSN; - long beyondTruncTxId = 1; - long txid = 1; - for (long i = 0; i < 3; i++) { - long start = txid; - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 10; j++) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid++); - CompletableFuture dlsn = writer.write(record); - - if (i == 1 && j == 2) { - truncDLSN = Utils.ioResult(dlsn); - } else if (i == 2 && j == 3) { - beyondTruncDLSN = Utils.ioResult(dlsn); - beyondTruncTxId = record.getTransactionId(); - } else if (j == 10) { - Utils.ioResult(dlsn); - } - } - - writer.close(); - } - - { - LogReader reader = dlm.getInputStream(DLSN.InitialDLSN); - LogRecordWithDLSN record = reader.readNext(false); - assertTrue((record != null) && (record.getDlsn().compareTo(DLSN.InitialDLSN) == 0)); - reader.close(); - } - - Map segmentList = DLMTestUtil.readLogSegments(zookeeperClient, - LogMetadata.getLogSegmentsPath(uri, name, confLocal.getUnpartitionedStreamName())); - - LOG.info("Read segments before truncating first segment : {}", segmentList); - - MetadataUpdater updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater( - confLocal, metadataStore); - Utils.ioResult(updater.setLogSegmentTruncated(segmentList.get(1L))); - - segmentList = DLMTestUtil.readLogSegments(zookeeperClient, - LogMetadata.getLogSegmentsPath(uri, name, confLocal.getUnpartitionedStreamName())); - - LOG.info("Read segments after truncated first segment : {}", segmentList); - - { - LogReader reader = dlm.getInputStream(DLSN.InitialDLSN); - LogRecordWithDLSN record = reader.readNext(false); - assertTrue("Unexpected record : " + record, - (record != null) && (record.getDlsn().compareTo(new DLSN(2, 0, 0)) == 0)); - reader.close(); - } - - { - LogReader reader = dlm.getInputStream(1); - LogRecordWithDLSN record = reader.readNext(false); - assertTrue((record != null) && (record.getDlsn().compareTo(new DLSN(2, 0, 0)) == 0)); - reader.close(); - } - - updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(confLocal, metadataStore); - Utils.ioResult(updater.setLogSegmentActive(segmentList.get(1L))); - - segmentList = DLMTestUtil.readLogSegments(zookeeperClient, - LogMetadata.getLogSegmentsPath(uri, name, confLocal.getUnpartitionedStreamName())); - - LOG.info("Read segments after marked first segment as active : {}", segmentList); - - updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(confLocal, metadataStore); - Utils.ioResult(updater.setLogSegmentTruncated(segmentList.get(2L))); - - segmentList = DLMTestUtil.readLogSegments(zookeeperClient, - LogMetadata.getLogSegmentsPath(uri, name, confLocal.getUnpartitionedStreamName())); - - LOG.info("Read segments after truncated second segment : {}", segmentList); - - { - AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InitialDLSN); - long expectedTxId = 1L; - boolean exceptionEncountered = false; - try { - for (int i = 0; i < 3 * 10; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - DLMTestUtil.verifyLargeLogRecord(record); - assertEquals(expectedTxId, record.getTransactionId()); - expectedTxId++; - } - } catch (AlreadyTruncatedTransactionException exc) { - exceptionEncountered = true; - } - assertTrue(exceptionEncountered); - Utils.close(reader); - } - - updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(conf, metadataStore); - Utils.ioResult(updater.setLogSegmentActive(segmentList.get(2L))); - - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - assertTrue(Utils.ioResult(writer.truncate(truncDLSN))); - BKLogWriteHandler handler = writer.getCachedWriteHandler(); - List cachedSegments = handler.getCachedLogSegments(LogSegmentMetadata.COMPARATOR); - for (LogSegmentMetadata segment: cachedSegments) { - if (segment.getLastDLSN().compareTo(truncDLSN) < 0) { - assertTrue(segment.isTruncated()); - assertTrue(!segment.isPartiallyTruncated()); - } else if (segment.getFirstDLSN().compareTo(truncDLSN) < 0) { - assertTrue(!segment.isTruncated()); - assertTrue(segment.isPartiallyTruncated()); - } else { - assertTrue(!segment.isTruncated()); - assertTrue(!segment.isPartiallyTruncated()); - } - } - - segmentList = DLMTestUtil.readLogSegments(zookeeperClient, - LogMetadata.getLogSegmentsPath(uri, name, conf.getUnpartitionedStreamName())); - - assertTrue(segmentList.get(truncDLSN.getLogSegmentSequenceNo()) - .getMinActiveDLSN().compareTo(truncDLSN) == 0); - - { - LogReader reader = dlm.getInputStream(DLSN.InitialDLSN); - LogRecordWithDLSN record = reader.readNext(false); - assertTrue(record != null); - assertEquals(truncDLSN, record.getDlsn()); - reader.close(); - } - - { - LogReader reader = dlm.getInputStream(1); - LogRecordWithDLSN record = reader.readNext(false); - assertTrue(record != null); - assertEquals(truncDLSN, record.getDlsn()); - reader.close(); - } - - { - AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InitialDLSN); - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertTrue(record != null); - assertEquals(truncDLSN, record.getDlsn()); - Utils.close(reader); - } - - - { - LogReader reader = dlm.getInputStream(beyondTruncDLSN); - LogRecordWithDLSN record = reader.readNext(false); - assertTrue(record != null); - assertEquals(beyondTruncDLSN, record.getDlsn()); - reader.close(); - } - - { - LogReader reader = dlm.getInputStream(beyondTruncTxId); - LogRecordWithDLSN record = reader.readNext(false); - assertTrue(record != null); - assertEquals(beyondTruncDLSN, record.getDlsn()); - assertEquals(beyondTruncTxId, record.getTransactionId()); - reader.close(); - } - - { - AsyncLogReader reader = dlm.getAsyncLogReader(beyondTruncDLSN); - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertTrue(record != null); - assertEquals(beyondTruncDLSN, record.getDlsn()); - Utils.close(reader); - } - - dlm.close(); - zookeeperClient.close(); - } - - @Test(timeout = 60000) - public void testDeleteLog() throws Exception { - String name = "delete-log-should-delete-ledgers"; - DistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - // Create the log and write some records - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long j = 1; j <= DEFAULT_SEGMENT_SIZE; j++) { - writer.write(DLMTestUtil.getLogRecordInstance(txid++)); - } - BKLogSegmentWriter perStreamLogWriter = writer.getCachedLogWriter(); - writer.closeAndComplete(); - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - assertNotNull(zkc.exists(blplm.completedLedgerZNode(txid, txid - 1, - perStreamLogWriter.getLogSegmentSequenceNumber()), false)); - Utils.ioResult(blplm.asyncClose()); - - // Should be able to open the underline ledger using BK client - long ledgerId = perStreamLogWriter.getLogSegmentId(); - BKNamespaceDriver driver = (BKNamespaceDriver) dlm.getNamespaceDriver(); - driver.getReaderBKC().get().openLedgerNoRecovery(ledgerId, - BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes(UTF_8)); - // Delete the log and we shouldn't be able the open the ledger - dlm.delete(); - try { - driver.getReaderBKC().get().openLedgerNoRecovery(ledgerId, - BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes(UTF_8)); - fail("Should fail to open ledger after we delete the log"); - } catch (BKException.BKNoSuchLedgerExistsOnMetadataServerException e) { - // ignore - } - // delete again should not throw any exception - try { - dlm.delete(); - } catch (IOException ioe) { - fail("Delete log twice should not throw any exception"); - } - dlm.close(); - } - - @Test(timeout = 60000) - public void testSyncLogWithLedgerMetadata() throws Exception { - - String application = "myapplication"; - String component = "mycomponent"; - String custom = "mycustommetadata"; - LedgerMetadata ledgerMetadata = new LedgerMetadata(); - ledgerMetadata.setApplication(application); - ledgerMetadata.setComponent(component); - ledgerMetadata.addCustomMetadata("custom", custom); - - BKDistributedLogManager dlm = createNewDLM(conf, "distrlog-writemetadata"); - - BKSyncLogWriter sync = dlm.openLogWriter(ledgerMetadata); - sync.write(DLMTestUtil.getLogRecordInstance(1)); - - LedgerHandle lh = getLedgerHandle(sync.getCachedLogWriter()); - Map customMeta = lh.getCustomMetadata(); - assertEquals(application, new String(customMeta.get("application"), UTF_8)); - assertEquals(component, new String(customMeta.get("component"), UTF_8)); - assertEquals(custom, new String(customMeta.get("custom"), UTF_8)); - - sync.closeAndComplete(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testAsyncLogWithLedgerMetadata() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setWriteLockEnabled(false); - - BKDistributedLogManager dlm = createNewDLM(confLocal, "distrlog-writemetadata-async"); - - String application = "myapplication"; - String custom = "mycustommetadata"; - LedgerMetadata ledgerMetadata = new LedgerMetadata(); - ledgerMetadata.setApplication(application); - ledgerMetadata.addCustomMetadata("custom", custom); - - AsyncLogWriter async = Utils.ioResult(dlm.openAsyncLogWriter(ledgerMetadata)); - Utils.ioResult(async.write(DLMTestUtil.getLogRecordInstance(2))); - - LedgerHandle lh = getLedgerHandle(((BKAsyncLogWriter) async).getCachedLogWriter()); - Map customMeta = lh.getCustomMetadata(); - assertEquals(application, new String(customMeta.get("application"), UTF_8)); - assertNull(customMeta.get("component")); - assertEquals(custom, new String(customMeta.get("custom"), UTF_8)); - - Utils.ioResult(async.asyncClose()); - dlm.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogNamespace.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogNamespace.java deleted file mode 100644 index d0372612fd5..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKDistributedLogNamespace.java +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Sets; -import java.io.IOException; -import java.net.URI; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.api.LogWriter; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.callback.NamespaceListener; -import org.apache.distributedlog.exceptions.AlreadyClosedException; -import org.apache.distributedlog.exceptions.InvalidStreamNameException; -import org.apache.distributedlog.exceptions.LockingException; -import org.apache.distributedlog.exceptions.ZKException; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.util.DLUtils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test Cases for {@link Namespace}. - */ -public class TestBKDistributedLogNamespace extends TestDistributedLogBase { - - @Rule - public TestName runtime = new TestName(); - - static final Logger LOG = LoggerFactory.getLogger(TestBKDistributedLogNamespace.class); - - protected static DistributedLogConfiguration conf = - new DistributedLogConfiguration().setLockTimeout(10) - .setEnableLedgerAllocatorPool(true).setLedgerAllocatorPoolName("test"); - - private ZooKeeperClient zooKeeperClient; - - @Before - public void setup() throws Exception { - zooKeeperClient = - TestZooKeeperClientBuilder.newBuilder() - .uri(createDLMURI("/")) - .build(); - } - - @After - public void teardown() throws Exception { - zooKeeperClient.close(); - } - - @Test(timeout = 60000) - public void testCreateLogPath0() throws Exception { - createLogPathTest("/create/log/path/" + runtime.getMethodName()); - } - - @Test(timeout = 60000) - public void testCreateLogPath1() throws Exception { - createLogPathTest("create/log/path/" + runtime.getMethodName()); - } - - private void createLogPathTest(String logName) throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - ensureURICreated(zooKeeperClient.get(), uri); - DistributedLogConfiguration newConf = new DistributedLogConfiguration(); - newConf.addConfiguration(conf); - newConf.setCreateStreamIfNotExists(false); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(newConf).uri(uri).build(); - DistributedLogManager dlm = namespace.openLog(logName); - LogWriter writer; - try { - writer = dlm.startLogSegmentNonPartitioned(); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - writer.commit(); - fail("Should fail to write data if stream doesn't exist."); - } catch (IOException ioe) { - // expected - } - dlm.close(); - } - - @Test(timeout = 60000) - public void testCreateIfNotExists() throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - ensureURICreated(zooKeeperClient.get(), uri); - DistributedLogConfiguration newConf = new DistributedLogConfiguration(); - newConf.addConfiguration(conf); - newConf.setCreateStreamIfNotExists(false); - String streamName = "test-stream"; - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(newConf).uri(uri).build(); - DistributedLogManager dlm = namespace.openLog(streamName); - LogWriter writer; - try { - writer = dlm.startLogSegmentNonPartitioned(); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - fail("Should fail to write data if stream doesn't exist."); - } catch (IOException ioe) { - // expected - } - dlm.close(); - - // create the stream - namespace.createLog(streamName); - - DistributedLogManager newDLM = namespace.openLog(streamName); - LogWriter newWriter = newDLM.startLogSegmentNonPartitioned(); - newWriter.write(DLMTestUtil.getLogRecordInstance(1L)); - newWriter.close(); - newDLM.close(); - } - - @Test(timeout = 60000) - public void testInvalidStreamName() throws Exception { - assertFalse(DLUtils.isReservedStreamName("test")); - assertTrue(DLUtils.isReservedStreamName(".test")); - - URI uri = createDLMURI("/" + runtime.getMethodName()); - - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf).uri(uri).build(); - - try { - namespace.openLog(".test1"); - fail("Should fail to create invalid stream .test"); - } catch (InvalidStreamNameException isne) { - // expected - } - - DistributedLogManager dlm = namespace.openLog("test1"); - LogWriter writer = dlm.startLogSegmentNonPartitioned(); - writer.write(DLMTestUtil.getLogRecordInstance(1)); - writer.close(); - dlm.close(); - - try { - namespace.openLog(".test2"); - fail("Should fail to create invalid stream .test2"); - } catch (InvalidStreamNameException isne) { - // expected - } - - try { - namespace.openLog("/ test2"); - fail("Should fail to create invalid stream / test2"); - } catch (InvalidStreamNameException isne) { - // expected - } - - try { - char[] chars = new char[6]; - for (int i = 0; i < chars.length; i++) { - chars[i] = 'a'; - } - chars[0] = 0; - String streamName = new String(chars); - namespace.openLog(streamName); - fail("Should fail to create invalid stream " + streamName); - } catch (InvalidStreamNameException isne) { - // expected - } - - try { - char[] chars = new char[6]; - for (int i = 0; i < chars.length; i++) { - chars[i] = 'a'; - } - chars[3] = '\u0010'; - String streamName = new String(chars); - namespace.openLog(streamName); - fail("Should fail to create invalid stream " + streamName); - } catch (InvalidStreamNameException isne) { - // expected - } - - DistributedLogManager newDLM = - namespace.openLog("test_2-3"); - LogWriter newWriter = newDLM.startLogSegmentNonPartitioned(); - newWriter.write(DLMTestUtil.getLogRecordInstance(1)); - newWriter.close(); - newDLM.close(); - - Iterator streamIter = namespace.getLogs(); - Set streamSet = Sets.newHashSet(streamIter); - - assertEquals(2, streamSet.size()); - assertTrue(streamSet.contains("test1")); - assertTrue(streamSet.contains("test_2-3")); - - namespace.close(); - } - - @Test(timeout = 60000) - public void testNamespaceListener() throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - zooKeeperClient.get().create(uri.getPath(), new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf).uri(uri).build(); - final CountDownLatch[] latches = new CountDownLatch[3]; - for (int i = 0; i < 3; i++) { - latches[i] = new CountDownLatch(1); - } - final AtomicInteger numUpdates = new AtomicInteger(0); - final AtomicInteger numFailures = new AtomicInteger(0); - final AtomicReference> receivedStreams = new AtomicReference>(null); - namespace.registerNamespaceListener(new NamespaceListener() { - @Override - public void onStreamsChanged(Iterator streams) { - Set streamSet = Sets.newHashSet(streams); - int updates = numUpdates.incrementAndGet(); - if (streamSet.size() != updates - 1) { - numFailures.incrementAndGet(); - } - - receivedStreams.set(streamSet); - latches[updates - 1].countDown(); - } - }); - latches[0].await(); - namespace.createLog("test1"); - latches[1].await(); - namespace.createLog("test2"); - latches[2].await(); - assertEquals(0, numFailures.get()); - assertNotNull(receivedStreams.get()); - Set streamSet = new HashSet(); - streamSet.addAll(receivedStreams.get()); - assertEquals(2, receivedStreams.get().size()); - assertEquals(2, streamSet.size()); - assertTrue(streamSet.contains("test1")); - assertTrue(streamSet.contains("test2")); - } - - private void initDlogMeta(String dlNamespace, String un, String streamName) throws Exception { - URI uri = createDLMURI(dlNamespace); - DistributedLogConfiguration newConf = new DistributedLogConfiguration(); - newConf.addConfiguration(conf); - newConf.setCreateStreamIfNotExists(true); - newConf.setZkAclId(un); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(newConf).uri(uri).build(); - DistributedLogManager dlm = namespace.openLog(streamName); - LogWriter writer = dlm.startLogSegmentNonPartitioned(); - for (int i = 0; i < 10; i++) { - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - } - writer.close(); - dlm.close(); - namespace.close(); - } - - @Test(timeout = 60000) - public void testAclPermsZkAccessConflict() throws Exception { - - String namespace = "/" + runtime.getMethodName(); - initDlogMeta(namespace, "test-un", "test-stream"); - URI uri = createDLMURI(namespace); - - ZooKeeperClient zkc = TestZooKeeperClientBuilder.newBuilder() - .name("unpriv") - .uri(uri) - .build(); - - try { - zkc.get().create(uri.getPath() + "/test-stream/test-garbage", - new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - fail("write should have failed due to perms"); - } catch (KeeperException.NoAuthException ex) { - LOG.info("caught exception trying to write with no perms", ex); - } - - try { - zkc.get().setData(uri.getPath() + "/test-stream", new byte[0], 0); - fail("write should have failed due to perms"); - } catch (KeeperException.NoAuthException ex) { - LOG.info("caught exception trying to write with no perms", ex); - } - } - - @Test(timeout = 60000) - public void testAclPermsZkAccessNoConflict() throws Exception { - - String namespace = "/" + runtime.getMethodName(); - initDlogMeta(namespace, "test-un", "test-stream"); - URI uri = createDLMURI(namespace); - - ZooKeeperClient zkc = TestZooKeeperClientBuilder.newBuilder() - .name("unpriv") - .uri(uri) - .build(); - - zkc.get().getChildren(uri.getPath() + "/test-stream", false, new Stat()); - zkc.get().getData(uri.getPath() + "/test-stream", false, new Stat()); - } - - @Test(timeout = 60000) - public void testAclModifyPermsDlmConflict() throws Exception { - String streamName = "test-stream"; - - // Reopening and writing again with the same un will succeed. - initDlogMeta("/" + runtime.getMethodName(), "test-un", streamName); - - try { - // Reopening and writing again with a different un will fail. - initDlogMeta("/" + runtime.getMethodName(), "not-test-un", streamName); - fail("Write should have failed due to perms"); - } catch (ZKException ex) { - LOG.info("Caught exception trying to write with no perms", ex); - assertEquals(KeeperException.Code.NOAUTH, ex.getKeeperExceptionCode()); - } catch (Exception ex) { - LOG.info("Caught wrong exception trying to write with no perms", ex); - fail("Wrong exception " + ex.getClass().getName() + " expected " + LockingException.class.getName()); - } - - // Should work again. - initDlogMeta("/" + runtime.getMethodName(), "test-un", streamName); - } - - @Test(timeout = 60000) - public void testAclModifyPermsDlmNoConflict() throws Exception { - String streamName = "test-stream"; - - // Establish the uri. - initDlogMeta("/" + runtime.getMethodName(), "test-un", streamName); - - // Reopening and writing again with the same un will succeed. - initDlogMeta("/" + runtime.getMethodName(), "test-un", streamName); - } - - static void validateBadAllocatorConfiguration(DistributedLogConfiguration conf, URI uri) throws Exception { - try { - BKNamespaceDriver.validateAndGetFullLedgerAllocatorPoolPath(conf, uri); - fail("Should throw exception when bad allocator configuration provided"); - } catch (IOException ioe) { - // expected - } - } - - @Test(timeout = 60000) - public void testValidateAndGetFullLedgerAllocatorPoolPath() throws Exception { - DistributedLogConfiguration testConf = new DistributedLogConfiguration(); - testConf.setEnableLedgerAllocatorPool(true); - - String namespace = "/" + runtime.getMethodName(); - URI uri = createDLMURI(namespace); - - testConf.setLedgerAllocatorPoolName("test"); - - testConf.setLedgerAllocatorPoolPath("test"); - validateBadAllocatorConfiguration(testConf, uri); - - testConf.setLedgerAllocatorPoolPath("."); - validateBadAllocatorConfiguration(testConf, uri); - - testConf.setLedgerAllocatorPoolPath(".."); - validateBadAllocatorConfiguration(testConf, uri); - - testConf.setLedgerAllocatorPoolPath("./"); - validateBadAllocatorConfiguration(testConf, uri); - - testConf.setLedgerAllocatorPoolPath(".test/"); - validateBadAllocatorConfiguration(testConf, uri); - - testConf.setLedgerAllocatorPoolPath(".test"); - testConf.setLedgerAllocatorPoolName(null); - validateBadAllocatorConfiguration(testConf, uri); - } - - @Test(timeout = 60000) - public void testUseNamespaceAfterCloseShouldFailFast() throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf) - .uri(uri) - .build(); - // before closing the namespace, no exception should be thrown - String logName = "test-stream"; - // create a log - namespace.createLog(logName); - // log exists - Assert.assertTrue(namespace.logExists(logName)); - // create a dlm - DistributedLogManager dlm = namespace.openLog(logName); - // do some writes - BKAsyncLogWriter writer = (BKAsyncLogWriter) (dlm.startAsyncLogSegmentNonPartitioned()); - for (long i = 0; i < 3; i++) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(i); - writer.write(record); - } - writer.closeAndComplete(); - // do some reads - LogReader reader = dlm.getInputStream(0); - for (long i = 0; i < 3; i++) { - Assert.assertEquals(reader.readNext(false).getTransactionId(), i); - } - namespace.deleteLog(logName); - Assert.assertFalse(namespace.logExists(logName)); - - // now try to close the namespace - namespace.close(); - try { - namespace.createLog(logName); - fail("Should throw exception after namespace is closed"); - } catch (AlreadyClosedException e) { - // No-ops - } - try { - namespace.openLog(logName); - fail("Should throw exception after namespace is closed"); - } catch (AlreadyClosedException e) { - // No-ops - } - try { - namespace.logExists(logName); - fail("Should throw exception after namespace is closed"); - } catch (AlreadyClosedException e) { - // No-ops - } - try { - namespace.getLogs(); - fail("Should throw exception after namespace is closed"); - } catch (AlreadyClosedException e) { - // No-ops - } - try { - namespace.deleteLog(logName); - fail("Should throw exception after namespace is closed"); - } catch (AlreadyClosedException e) { - // No-ops - } - try { - namespace.createAccessControlManager(); - fail("Should throw exception after namespace is closed"); - } catch (AlreadyClosedException e) { - // No-ops - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogReadHandler.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogReadHandler.java deleted file mode 100644 index 323a0f59fe1..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogReadHandler.java +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogWriter; -import org.apache.distributedlog.exceptions.LogNotFoundException; -import org.apache.distributedlog.exceptions.OwnershipAcquireFailedException; -import org.apache.distributedlog.logsegment.LogSegmentFilter; -import org.apache.distributedlog.util.Utils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Test {@link BKLogReadHandler}. - */ -public class TestBKLogReadHandler extends TestDistributedLogBase { - - static final Logger LOG = LoggerFactory.getLogger(TestBKLogReadHandler.class); - - @Rule - public TestName runtime = new TestName(); - - private void prepareLogSegmentsNonPartitioned(String name, - int numSegments, int numEntriesPerSegment) throws Exception { - DistributedLogManager dlm = createNewDLM(conf, name); - long txid = 1; - for (int sid = 0; sid < numSegments; ++sid) { - LogWriter out = dlm.startLogSegmentNonPartitioned(); - for (int eid = 0; eid < numEntriesPerSegment; ++eid) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid); - out.write(record); - ++txid; - } - out.close(); - } - dlm.close(); - } - - @Test(timeout = 60000) - public void testGetFirstDLSNWithOpenLedger() throws Exception { - String dlName = runtime.getMethodName(); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(0); - - int numEntriesPerSegment = 10; - DistributedLogManager dlm1 = createNewDLM(confLocal, dlName); - long txid = 1; - - ArrayList> futures = new ArrayList>(numEntriesPerSegment); - AsyncLogWriter out = dlm1.startAsyncLogSegmentNonPartitioned(); - for (int eid = 0; eid < numEntriesPerSegment; ++eid) { - futures.add(out.write(DLMTestUtil.getLogRecordInstance(txid))); - ++txid; - } - Utils.ioResult(FutureUtils.collect(futures)); - // commit - LogRecord controlRecord = new LogRecord(txid, DistributedLogConstants.CONTROL_RECORD_CONTENT); - controlRecord.setControl(); - Utils.ioResult(out.write(controlRecord)); - - DLSN last = dlm1.getLastDLSN(); - assertEquals(new DLSN(1, 9, 0), last); - DLSN first = Utils.ioResult(dlm1.getFirstDLSNAsync()); - assertEquals(new DLSN(1, 0, 0), first); - Utils.close(out); - } - - @Test(timeout = 60000) - public void testGetFirstDLSNNoLogSegments() throws Exception { - String dlName = runtime.getMethodName(); - BKDistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = dlm.createReadHandler(); - CompletableFuture futureRecord = readHandler.asyncGetFirstLogRecord(); - try { - Utils.ioResult(futureRecord); - fail("should have thrown exception"); - } catch (LogNotFoundException ex) { - } - } - - @Test(timeout = 60000) - public void testGetFirstDLSNWithLogSegments() throws Exception { - String dlName = runtime.getMethodName(); - BKDistributedLogManager dlm = createNewDLM(conf, dlName); - DLMTestUtil.generateCompletedLogSegments(dlm, conf, 3, 3); - BKLogReadHandler readHandler = dlm.createReadHandler(); - CompletableFuture futureRecord = readHandler.asyncGetFirstLogRecord(); - try { - LogRecordWithDLSN record = Utils.ioResult(futureRecord); - assertEquals(new DLSN(1, 0, 0), record.getDlsn()); - } catch (Exception ex) { - fail("should not have thrown exception: " + ex); - } - } - - @Test(timeout = 60000) - public void testGetFirstDLSNAfterCleanTruncation() throws Exception { - String dlName = runtime.getMethodName(); - prepareLogSegmentsNonPartitioned(dlName, 3, 10); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = - ((BKDistributedLogManager) dlm).createReadHandler(); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - CompletableFuture futureSuccess = writer.truncate(new DLSN(2, 0, 0)); - Boolean success = Utils.ioResult(futureSuccess); - assertTrue(success); - CompletableFuture futureRecord = readHandler.asyncGetFirstLogRecord(); - LogRecordWithDLSN record = Utils.ioResult(futureRecord); - assertEquals(new DLSN(2, 0, 0), record.getDlsn()); - } - - @Test(timeout = 60000) - public void testGetFirstDLSNAfterPartialTruncation() throws Exception { - String dlName = runtime.getMethodName(); - prepareLogSegmentsNonPartitioned(dlName, 3, 10); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = - ((BKDistributedLogManager) dlm).createReadHandler(); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - - // Only truncates at ledger boundary. - CompletableFuture futureSuccess = writer.truncate(new DLSN(2, 5, 0)); - Boolean success = Utils.ioResult(futureSuccess); - assertTrue(success); - CompletableFuture futureRecord = readHandler.asyncGetFirstLogRecord(); - LogRecordWithDLSN record = Utils.ioResult(futureRecord); - assertEquals(new DLSN(2, 0, 0), record.getDlsn()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountEmptyLedger() throws Exception { - String dlName = runtime.getMethodName(); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(DLSN.InitialDLSN); - try { - Utils.ioResult(count); - fail("log is empty, should have returned log empty ex"); - } catch (LogNotFoundException ex) { - } - } - - @Test(timeout = 60000) - public void testGetLogRecordCountTotalCount() throws Exception { - String dlName = runtime.getMethodName(); - prepareLogSegmentsNonPartitioned(dlName, 11, 3); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(DLSN.InitialDLSN); - assertEquals(33, Utils.ioResult(count).longValue()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountAtLedgerBoundary() throws Exception { - String dlName = runtime.getMethodName(); - prepareLogSegmentsNonPartitioned(dlName, 11, 3); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(2, 0, 0)); - assertEquals(30, Utils.ioResult(count).longValue()); - count = readHandler.asyncGetLogRecordCount(new DLSN(3, 0, 0)); - assertEquals(27, Utils.ioResult(count).longValue()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountPastEnd() throws Exception { - String dlName = runtime.getMethodName(); - prepareLogSegmentsNonPartitioned(dlName, 11, 3); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(12, 0, 0)); - assertEquals(0, Utils.ioResult(count).longValue()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountLastRecord() throws Exception { - String dlName = runtime.getMethodName(); - prepareLogSegmentsNonPartitioned(dlName, 11, 3); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(11, 2, 0)); - assertEquals(1, Utils.ioResult(count).longValue()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountInteriorRecords() throws Exception { - String dlName = runtime.getMethodName(); - prepareLogSegmentsNonPartitioned(dlName, 5, 10); - DistributedLogManager dlm = createNewDLM(conf, dlName); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(3, 5, 0)); - assertEquals(25, Utils.ioResult(count).longValue()); - count = readHandler.asyncGetLogRecordCount(new DLSN(2, 5, 0)); - assertEquals(35, Utils.ioResult(count).longValue()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountWithControlRecords() throws Exception { - DistributedLogManager dlm = createNewDLM(conf, runtime.getMethodName()); - long txid = 1; - txid += DLMTestUtil.generateLogSegmentNonPartitioned(dlm, 5, 5, txid); - txid += DLMTestUtil.generateLogSegmentNonPartitioned(dlm, 0, 10, txid); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(1, 0, 0)); - assertEquals(15, Utils.ioResult(count).longValue()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountWithAllControlRecords() throws Exception { - DistributedLogManager dlm = createNewDLM(conf, runtime.getMethodName()); - long txid = 1; - txid += DLMTestUtil.generateLogSegmentNonPartitioned(dlm, 5, 0, txid); - txid += DLMTestUtil.generateLogSegmentNonPartitioned(dlm, 10, 0, txid); - BKLogReadHandler readHandler = ((BKDistributedLogManager) dlm).createReadHandler(); - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(1, 0, 0)); - assertEquals(0, Utils.ioResult(count).longValue()); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountWithSingleInProgressLedger() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - - AsyncLogWriter out = bkdlm.startAsyncLogSegmentNonPartitioned(); - int txid = 1; - - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - - BKLogReadHandler readHandler = bkdlm.createReadHandler(); - List ledgerList = Utils.ioResult( - readHandler.readLogSegmentsFromStore( - LogSegmentMetadata.COMPARATOR, - LogSegmentFilter.DEFAULT_FILTER, - null - ) - ).getValue(); - assertEquals(1, ledgerList.size()); - assertTrue(ledgerList.get(0).isInProgress()); - - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(1, 0, 0)); - assertEquals(2, Utils.ioResult(count).longValue()); - - Utils.close(out); - } - - @Test(timeout = 60000) - public void testGetLogRecordCountWithCompletedAndInprogressLedgers() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - - long txid = 1; - txid += DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5, txid); - AsyncLogWriter out = bkdlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - - BKLogReadHandler readHandler = bkdlm.createReadHandler(); - List ledgerList = Utils.ioResult( - readHandler.readLogSegmentsFromStore( - LogSegmentMetadata.COMPARATOR, - LogSegmentFilter.DEFAULT_FILTER, - null) - ).getValue(); - assertEquals(2, ledgerList.size()); - assertFalse(ledgerList.get(0).isInProgress()); - assertTrue(ledgerList.get(1).isInProgress()); - - CompletableFuture count = null; - count = readHandler.asyncGetLogRecordCount(new DLSN(1, 0, 0)); - assertEquals(7, Utils.ioResult(count).longValue()); - - Utils.close(out); - } - - @Test(timeout = 60000) - public void testLockStreamWithMissingLog() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - BKLogReadHandler readHandler = bkdlm.createReadHandler(); - try { - Utils.ioResult(readHandler.lockStream()); - fail("Should fail lock stream if log not found"); - } catch (LogNotFoundException ex) { - } - - BKLogReadHandler subscriberReadHandler = bkdlm.createReadHandler(Optional.of("test-subscriber")); - try { - Utils.ioResult(subscriberReadHandler.lockStream()); - fail("Subscriber should fail lock stream if log not found"); - } catch (LogNotFoundException ex) { - // expected - } - } - - @Test(timeout = 60000) - public void testLockStreamDifferentSubscribers() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5, 1); - BKLogReadHandler readHandler = bkdlm.createReadHandler(); - Utils.ioResult(readHandler.lockStream()); - - // two subscribers could lock stream in parallel - BKDistributedLogManager bkdlm10 = createNewDLM(conf, streamName); - BKLogReadHandler s10Handler = - bkdlm10.createReadHandler(Optional.of("s1")); - Utils.ioResult(s10Handler.lockStream()); - BKDistributedLogManager bkdlm20 = createNewDLM(conf, streamName); - BKLogReadHandler s20Handler = - bkdlm20.createReadHandler(Optional.of("s2")); - Utils.ioResult(s20Handler.lockStream()); - - readHandler.asyncClose(); - bkdlm.close(); - s10Handler.asyncClose(); - bkdlm10.close(); - s20Handler.asyncClose(); - bkdlm20.close(); - } - - @Test(timeout = 60000) - public void testLockStreamSameSubscriber() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5, 1); - BKLogReadHandler readHandler = bkdlm.createReadHandler(); - Utils.ioResult(readHandler.lockStream()); - - // same subscrbiers couldn't lock stream in parallel - BKDistributedLogManager bkdlm10 = createNewDLM(conf, streamName); - BKLogReadHandler s10Handler = - bkdlm10.createReadHandler(Optional.of("s1")); - Utils.ioResult(s10Handler.lockStream()); - - BKDistributedLogManager bkdlm11 = createNewDLM(conf, streamName); - BKLogReadHandler s11Handler = - bkdlm11.createReadHandler(Optional.of("s1")); - try { - Utils.ioResult(s11Handler.lockStream(), 10000, TimeUnit.MILLISECONDS); - fail("Should fail lock stream using same subscriber id"); - } catch (OwnershipAcquireFailedException oafe) { - // expected - } catch (TimeoutException te) { - // expected. - } - - readHandler.asyncClose(); - bkdlm.close(); - s10Handler.asyncClose(); - bkdlm10.close(); - s11Handler.asyncClose(); - bkdlm11.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogSegmentWriter.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogSegmentWriter.java deleted file mode 100644 index 89aab53e07c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogSegmentWriter.java +++ /dev/null @@ -1,789 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.feature.SettableFeatureProvider; -import org.apache.bookkeeper.stats.AlertStatsLogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.distributedlog.common.util.PermitLimiter; -import org.apache.distributedlog.exceptions.BKTransmitException; -import org.apache.distributedlog.exceptions.EndOfStreamException; -import org.apache.distributedlog.exceptions.WriteCancelledException; -import org.apache.distributedlog.exceptions.WriteException; -import org.apache.distributedlog.exceptions.ZKException; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.impl.logsegment.BKLogSegmentEntryWriter; -import org.apache.distributedlog.impl.metadata.BKDLConfig; -import org.apache.distributedlog.lock.SessionLockFactory; -import org.apache.distributedlog.lock.ZKDistributedLock; -import org.apache.distributedlog.lock.ZKSessionLockFactory; -import org.apache.distributedlog.util.ConfUtils; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - - - - -/** - * Test Case for BookKeeper Based Log Segment Writer. - */ -public class TestBKLogSegmentWriter extends TestDistributedLogBase { - - @Rule - public TestName runtime = new TestName(); - - private OrderedScheduler scheduler; - private OrderedScheduler lockStateExecutor; - private ZooKeeperClient zkc; - private ZooKeeperClient zkc0; - private BookKeeperClient bkc; - - @Before - @Override - public void setup() throws Exception { - super.setup(); - scheduler = OrderedScheduler.newSchedulerBuilder().numThreads(1).build(); - lockStateExecutor = OrderedScheduler.newSchedulerBuilder().numThreads(1).build(); - // build zookeeper client - URI uri = createDLMURI(""); - zkc = TestZooKeeperClientBuilder.newBuilder(conf) - .name("test-zkc") - .uri(uri) - .build(); - zkc0 = TestZooKeeperClientBuilder.newBuilder(conf) - .name("test-zkc0") - .uri(uri) - .build(); - // build bookkeeper client - BKDLConfig bkdlConfig = BKDLConfig.resolveDLConfig(zkc, uri); - bkc = BookKeeperClientBuilder.newBuilder() - .dlConfig(conf) - .name("test-bkc") - .ledgersPath(bkdlConfig.getBkLedgersPath()) - .zkServers(BKNamespaceDriver.getZKServersFromDLUri(uri)) - .build(); - } - - @After - @Override - public void teardown() throws Exception { - if (null != bkc) { - bkc.close(); - } - if (null != zkc) { - zkc.close(); - } - if (null != lockStateExecutor) { - lockStateExecutor.shutdown(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - super.teardown(); - } - - private DistributedLogConfiguration newLocalConf() { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - return confLocal; - } - - private ZKDistributedLock createLock(String path, - ZooKeeperClient zkClient, - boolean acquireLock) - throws Exception { - try { - Utils.ioResult(Utils.zkAsyncCreateFullPathOptimistic(zkClient, path, new byte[0], - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)); - } catch (ZKException zke) { - // node already exists - } - SessionLockFactory lockFactory = new ZKSessionLockFactory( - zkClient, - "test-lock", - lockStateExecutor, - 0, - Long.MAX_VALUE, - conf.getZKSessionTimeoutMilliseconds(), - NullStatsLogger.INSTANCE - ); - ZKDistributedLock lock = new ZKDistributedLock( - lockStateExecutor, - lockFactory, - path, - Long.MAX_VALUE, - NullStatsLogger.INSTANCE); - if (acquireLock) { - return Utils.ioResult(lock.asyncAcquire()); - } else { - return lock; - } - } - - private void closeWriterAndLock(BKLogSegmentWriter writer, - ZKDistributedLock lock) - throws Exception { - try { - Utils.ioResult(writer.asyncClose()); - } finally { - Utils.closeQuietly(lock); - } - } - - private void abortWriterAndLock(BKLogSegmentWriter writer, - ZKDistributedLock lock) - throws IOException { - try { - Utils.abort(writer, false); - } finally { - Utils.closeQuietly(lock); - } - } - - private BKLogSegmentWriter createLogSegmentWriter(DistributedLogConfiguration conf, - long logSegmentSequenceNumber, - long startTxId, - ZKDistributedLock lock) throws Exception { - LedgerHandle lh = bkc.get().createLedger(3, 2, 2, - BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes(UTF_8)); - return new BKLogSegmentWriter( - runtime.getMethodName(), - runtime.getMethodName(), - conf, - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION, - new BKLogSegmentEntryWriter(lh), - lock, - startTxId, - logSegmentSequenceNumber, - scheduler, - NullStatsLogger.INSTANCE, - NullStatsLogger.INSTANCE, - new AlertStatsLogger(NullStatsLogger.INSTANCE, "test"), - PermitLimiter.NULL_PERMIT_LIMITER, - new SettableFeatureProvider("", 0), - ConfUtils.getConstDynConf(conf)); - } - - private LedgerHandle openLedgerNoRecovery(LedgerHandle lh) throws Exception { - return bkc.get().openLedgerNoRecovery(lh.getId(), - BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes(UTF_8)); - } - - private LedgerHandle openLedger(LedgerHandle lh) throws Exception { - return bkc.get().openLedger(lh.getId(), - BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes(UTF_8)); - } - - private void fenceLedger(LedgerHandle lh) throws Exception { - bkc.get().openLedger(lh.getId(), BookKeeper.DigestType.CRC32, - conf.getBKDigestPW().getBytes(UTF_8)); - } - - /** - * Close a segment log writer should flush buffered data. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testCloseShouldFlush() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - // Use another lock to wait for writer releasing lock - ZKDistributedLock lock0 = createLock("/test/lock-" + runtime.getMethodName(), zkc0, false); - CompletableFuture lockFuture0 = lock0.asyncAcquire(); - // add 10 records - int numRecords = 10; - List> futureList = new ArrayList>(numRecords); - for (int i = 0; i < numRecords; i++) { - futureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i))); - } - assertEquals("Last tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should be -1", - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - // close the writer should flush buffered data and release lock - closeWriterAndLock(writer, lock); - Utils.ioResult(lockFuture0); - lock0.checkOwnership(); - assertEquals("Last tx id should still be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should become " + (numRecords - 1), - numRecords - 1, writer.getLastTxIdAcknowledged()); - assertEquals("Position should still be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - List dlsns = Utils.ioResult(FutureUtils.collect(futureList)); - assertEquals("All records should be written", - numRecords, dlsns.size()); - for (int i = 0; i < numRecords; i++) { - DLSN dlsn = dlsns.get(i); - assertEquals("Incorrent ledger sequence number", - 0L, dlsn.getLogSegmentSequenceNo()); - assertEquals("Incorrent entry id", - 0L, dlsn.getEntryId()); - assertEquals("Inconsistent slot id", - i, dlsn.getSlotId()); - } - assertEquals("Last DLSN should be " + dlsns.get(dlsns.size() - 1), - dlsns.get(dlsns.size() - 1), writer.getLastDLSN()); - LedgerHandle lh = getLedgerHandle(writer); - LedgerHandle readLh = openLedgerNoRecovery(lh); - assertTrue("Ledger " + lh.getId() + " should be closed", readLh.isClosed()); - assertEquals("There should be two entries in ledger " + lh.getId(), - 1L, readLh.getLastAddConfirmed()); - } - - /** - * Abort a segment log writer should just abort pending writes and not flush buffered data. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testAbortShouldNotFlush() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - // Use another lock to wait for writer releasing lock - ZKDistributedLock lock0 = createLock("/test/lock-" + runtime.getMethodName(), zkc0, false); - CompletableFuture lockFuture0 = lock0.asyncAcquire(); - // add 10 records - int numRecords = 10; - List> futureList = new ArrayList>(numRecords); - for (int i = 0; i < numRecords; i++) { - futureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i))); - } - assertEquals("Last tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should be -1", - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - // close the writer should flush buffered data and release lock - abortWriterAndLock(writer, lock); - Utils.ioResult(lockFuture0); - lock0.checkOwnership(); - assertEquals("Last tx id should still be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should still be " + (numRecords - 1), - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should still be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should still be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - - for (int i = 0; i < numRecords; i++) { - try { - Utils.ioResult(futureList.get(i)); - fail("Should be aborted record " + i + " with transmit exception"); - } catch (WriteCancelledException wce) { - assertTrue("Record " + i + " should be aborted because of ledger fenced", - wce.getCause() instanceof BKTransmitException); - BKTransmitException bkte = (BKTransmitException) wce.getCause(); - assertEquals("Record " + i + " should be aborted", - BKException.Code.InterruptedException, bkte.getBKResultCode()); - } - } - - // check no entries were written - LedgerHandle lh = getLedgerHandle(writer); - LedgerHandle readLh = openLedgerNoRecovery(lh); - assertTrue("Ledger " + lh.getId() + " should not be closed", readLh.isClosed()); - assertEquals("There should be no entries in ledger " + lh.getId(), - LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - } - - - /** - * Close a log segment writer that already detect ledger fenced, should not flush buffered data. - * And should throw exception on closing. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testCloseShouldNotFlushIfLedgerFenced() throws Exception { - testCloseShouldNotFlushIfInErrorState(BKException.Code.LedgerFencedException); - } - - /** - * Close a log segment writer that is already in error state, should not flush buffered data. - * - * @throws Exception - */ - void testCloseShouldNotFlushIfInErrorState(int rcToFailComplete) throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - // Use another lock to wait for writer releasing lock - ZKDistributedLock lock0 = createLock("/test/lock-" + runtime.getMethodName(), zkc0, false); - CompletableFuture lockFuture0 = lock0.asyncAcquire(); - // add 10 records - int numRecords = 10; - List> futureList = new ArrayList>(numRecords); - for (int i = 0; i < numRecords; i++) { - futureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i))); - } - assertEquals("Last tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should be -1", - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - writer.setTransmitResult(rcToFailComplete); - // close the writer should release lock but not flush data - try { - closeWriterAndLock(writer, lock); - fail("Close a log segment writer in error state should throw exception"); - } catch (BKTransmitException bkte) { - assertEquals("Inconsistent rc is thrown", - rcToFailComplete, bkte.getBKResultCode()); - } - Utils.ioResult(lockFuture0); - lock0.checkOwnership(); - assertEquals("Last tx id should still be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should still be " + (numRecords - 1), - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should still be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should still be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - - for (int i = 0; i < numRecords; i++) { - try { - Utils.ioResult(futureList.get(i)); - fail("Should be aborted record " + i + " with transmit exception"); - } catch (WriteCancelledException wce) { - assertTrue("Record " + i + " should be aborted because of ledger fenced", - wce.getCause() instanceof BKTransmitException); - BKTransmitException bkte = (BKTransmitException) wce.getCause(); - assertEquals("Record " + i + " should be aborted", - rcToFailComplete, bkte.getBKResultCode()); - } - } - - // check no entries were written - LedgerHandle lh = getLedgerHandle(writer); - LedgerHandle readLh = openLedgerNoRecovery(lh); - assertFalse("Ledger " + lh.getId() + " should not be closed", readLh.isClosed()); - assertEquals("There should be no entries in ledger " + lh.getId(), - LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - } - - /** - * Close the writer when ledger is fenced: it should release the lock, fail on flushing data and throw exception. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testCloseShouldFailIfLedgerFenced() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - // Use another lock to wait for writer releasing lock - ZKDistributedLock lock0 = createLock("/test/lock-" + runtime.getMethodName(), zkc0, false); - CompletableFuture lockFuture0 = lock0.asyncAcquire(); - // add 10 records - int numRecords = 10; - List> futureList = new ArrayList>(numRecords); - for (int i = 0; i < numRecords; i++) { - futureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i))); - } - assertEquals("Last tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should be -1", - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - // fence the ledger - fenceLedger(getLedgerHandle(writer)); - // close the writer: it should release the lock, fail on flushing data and throw exception - try { - closeWriterAndLock(writer, lock); - fail("Close a log segment writer when ledger is fenced should throw exception"); - } catch (BKTransmitException bkte) { - assertEquals("Inconsistent rc is thrown", - BKException.Code.LedgerFencedException, bkte.getBKResultCode()); - } - - Utils.ioResult(lockFuture0); - lock0.checkOwnership(); - - assertEquals("Last tx id should still be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should still be " + (numRecords - 1), - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should still be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should still be " + numRecords, - 10, writer.getPositionWithinLogSegment()); - - for (int i = 0; i < numRecords; i++) { - try { - Utils.ioResult(futureList.get(i)); - fail("Should be aborted record " + i + " with transmit exception"); - } catch (BKTransmitException bkte) { - assertEquals("Record " + i + " should be aborted", - BKException.Code.LedgerFencedException, bkte.getBKResultCode()); - } - } - - // check no entries were written - LedgerHandle lh = getLedgerHandle(writer); - LedgerHandle readLh = openLedgerNoRecovery(lh); - assertTrue("Ledger " + lh.getId() + " should be closed", readLh.isClosed()); - assertEquals("There should be no entries in ledger " + lh.getId(), - LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed()); - } - - /** - * Abort should wait for outstanding transmits to be completed and cancel buffered data. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testAbortShouldFailAllWrites() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - // Use another lock to wait for writer releasing lock - ZKDistributedLock lock0 = createLock("/test/lock-" + runtime.getMethodName(), zkc0, false); - CompletableFuture lockFuture0 = lock0.asyncAcquire(); - // add 10 records - int numRecords = 10; - List> futureList = new ArrayList>(numRecords); - for (int i = 0; i < numRecords; i++) { - futureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i))); - } - assertEquals("Last tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should be -1", - -1L, writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should be " + numRecords, - numRecords, writer.getPositionWithinLogSegment()); - - final CountDownLatch deferLatch = new CountDownLatch(1); - writer.getFuturePool().submit(() -> { - try { - deferLatch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.warn("Interrupted on deferring completion : ", e); - } - }); - - // transmit the buffered data - Utils.ioResult(writer.flush()); - - // add another 10 records - List> anotherFutureList = new ArrayList>(numRecords); - for (int i = numRecords; i < 2 * numRecords; i++) { - anotherFutureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i))); - } - assertEquals("Last tx id should become " + (2 * numRecords - 1), - 2 * numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should become " + (numRecords - 1), - (long) (numRecords - 1), writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should still be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should become " + (2 * numRecords), - 2 * numRecords, writer.getPositionWithinLogSegment()); - - // abort the writer: it waits for outstanding transmits and abort buffered data - abortWriterAndLock(writer, lock); - - Utils.ioResult(lockFuture0); - lock0.checkOwnership(); - - // release defer latch so completion would go through - deferLatch.countDown(); - - List dlsns = Utils.ioResult(FutureUtils.collect(futureList)); - assertEquals("All first 10 records should be written", - numRecords, dlsns.size()); - for (int i = 0; i < numRecords; i++) { - DLSN dlsn = dlsns.get(i); - assertEquals("Incorrent ledger sequence number", - 0L, dlsn.getLogSegmentSequenceNo()); - assertEquals("Incorrent entry id", - 0L, dlsn.getEntryId()); - assertEquals("Inconsistent slot id", - i, dlsn.getSlotId()); - } - for (int i = 0; i < numRecords; i++) { - try { - Utils.ioResult(anotherFutureList.get(i)); - fail("Should be aborted record " + (numRecords + i) + " with transmit exception"); - } catch (WriteCancelledException wce) { - // writes should be cancelled. - } - } - - assertEquals("Last tx id should still be " + (2 * numRecords - 1), - 2 * numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should be still " + (numRecords - 1), - (long) (numRecords - 1), writer.getLastTxIdAcknowledged()); - assertEquals("Last DLSN should become " + futureList.get(futureList.size() - 1), - dlsns.get(futureList.size() - 1), writer.getLastDLSN()); - assertEquals("Position should become " + 2 * numRecords, - 2 * numRecords, writer.getPositionWithinLogSegment()); - - // check only 1 entry were written - LedgerHandle lh = getLedgerHandle(writer); - LedgerHandle readLh = openLedgerNoRecovery(lh); - assertTrue("Ledger " + lh.getId() + " should not be closed", readLh.isClosed()); - assertEquals("Only one entry is written for ledger " + lh.getId(), - 0L, lh.getLastAddPushed()); - assertEquals("Only one entry is written for ledger " + lh.getId(), - 0L, readLh.getLastAddConfirmed()); - } - - /** - * Log Segment Writer should only update last tx id only for user records. - */ - @Test(timeout = 60000) - public void testUpdateLastTxIdForUserRecords() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - // add 10 records - int numRecords = 10; - List> futureList = new ArrayList>(numRecords); - for (int i = 0; i < numRecords; i++) { - futureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i))); - } - LogRecord controlRecord = DLMTestUtil.getLogRecordInstance(9999L); - controlRecord.setControl(); - futureList.add(writer.asyncWrite(controlRecord)); - assertEquals("Last tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last DLSN should be " + DLSN.InvalidDLSN, - DLSN.InvalidDLSN, writer.getLastDLSN()); - assertEquals("Position should be " + numRecords, - numRecords, writer.getPositionWithinLogSegment()); - - // close the writer to flush the output buffer - closeWriterAndLock(writer, lock); - - List dlsns = Utils.ioResult(FutureUtils.collect(futureList)); - assertEquals("All 11 records should be written", - numRecords + 1, dlsns.size()); - for (int i = 0; i < numRecords; i++) { - DLSN dlsn = dlsns.get(i); - assertEquals("Incorrent ledger sequence number", - 0L, dlsn.getLogSegmentSequenceNo()); - assertEquals("Incorrent entry id", - 0L, dlsn.getEntryId()); - assertEquals("Inconsistent slot id", - i, dlsn.getSlotId()); - } - DLSN dlsn = dlsns.get(numRecords); - assertEquals("Incorrent ledger sequence number", - 0L, dlsn.getLogSegmentSequenceNo()); - assertEquals("Incorrent entry id", - 1L, dlsn.getEntryId()); - assertEquals("Inconsistent slot id", - 0L, dlsn.getSlotId()); - - assertEquals("Last tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxId()); - assertEquals("Last acked tx id should be " + (numRecords - 1), - numRecords - 1, writer.getLastTxIdAcknowledged()); - assertEquals("Position should be " + numRecords, - numRecords, writer.getPositionWithinLogSegment()); - assertEquals("Last DLSN should be " + dlsn, - dlsns.get(numRecords - 1), writer.getLastDLSN()); - } - - /** - * Non durable write should fail if writer is closed. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testNondurableWriteAfterWriterIsClosed() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setDurableWriteEnabled(false); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - - // close the writer - closeWriterAndLock(writer, lock); - Utils.ioResult(writer.asyncClose()); - - try { - Utils.ioResult(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(1))); - fail("Should fail the write if the writer is closed"); - } catch (WriteException we) { - // expected - } - } - - /** - * Non durable write should fail if writer is marked as end of stream. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testNondurableWriteAfterEndOfStream() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setDurableWriteEnabled(false); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - - Utils.ioResult(writer.markEndOfStream()); - - try { - Utils.ioResult(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(1))); - fail("Should fail the write if the writer is marked as end of stream"); - } catch (EndOfStreamException we) { - // expected - } - - closeWriterAndLock(writer, lock); - } - - /** - * Non durable write should fail if the log segment is fenced. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testNondurableWriteAfterLedgerIsFenced() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setDurableWriteEnabled(false); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - - // fence the ledger - fenceLedger(getLedgerHandle(writer)); - - LogRecord record = DLMTestUtil.getLogRecordInstance(1); - record.setControl(); - try { - Utils.ioResult(writer.asyncWrite(record)); - fail("Should fail the writer if the log segment is already fenced"); - } catch (BKTransmitException bkte) { - // expected - assertEquals(BKException.Code.LedgerFencedException, bkte.getBKResultCode()); - } - - try { - Utils.ioResult(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(2))); - fail("Should fail the writer if the log segment is already fenced"); - } catch (WriteException we) { - // expected - } - - abortWriterAndLock(writer, lock); - } - - /** - * Non durable write should fail if writer is marked as end of stream. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testNondurableWrite() throws Exception { - DistributedLogConfiguration confLocal = newLocalConf(); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(Integer.MAX_VALUE); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setDurableWriteEnabled(false); - ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true); - BKLogSegmentWriter writer = - createLogSegmentWriter(confLocal, 0L, -1L, lock); - - assertEquals(DLSN.InvalidDLSN, - Utils.ioResult(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(2)))); - assertEquals(-1L, ((BKLogSegmentEntryWriter) writer.getEntryWriter()) - .getLedgerHandle().getLastAddPushed()); - - closeWriterAndLock(writer, lock); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogWriteHandler.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogWriteHandler.java deleted file mode 100644 index c2a631e7eb2..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKLogWriteHandler.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Set; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogWriter; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.bk.LedgerAllocator; -import org.apache.distributedlog.bk.LedgerAllocatorPool; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.util.FailpointUtils; -import org.apache.distributedlog.util.Utils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - - - -/** - * Test {@link BKLogWriteHandler}. - */ -public class TestBKLogWriteHandler extends TestDistributedLogBase { - - @Rule - public TestName runtime = new TestName(); - - /** - * Testcase: when write handler encounters exceptions on starting log segment - * it should abort the transaction and return the ledger to the pool. - */ - @Test(timeout = 60000) - public void testAbortTransactionOnStartLogSegment() throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - ensureURICreated(zkc, uri); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setEnableLedgerAllocatorPool(true); - confLocal.setLedgerAllocatorPoolCoreSize(1); - confLocal.setLedgerAllocatorPoolName("test-allocator-pool"); - - BKDistributedLogNamespace namespace = (BKDistributedLogNamespace) - NamespaceBuilder.newBuilder() - .conf(confLocal) - .uri(uri) - .build(); - DistributedLogManager dlm = namespace.openLog("test-stream"); - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_StartLogSegmentOnAssignLogSegmentSequenceNumber, - FailpointUtils.FailPointActions.FailPointAction_Throw); - try { - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1L))); - fail("Should fail opening the writer"); - } catch (IOException ioe) { - // expected - } finally { - FailpointUtils.removeFailpoint( - FailpointUtils.FailPointName.FP_StartLogSegmentOnAssignLogSegmentSequenceNumber); - } - - LedgerAllocator allocator = ((BKNamespaceDriver) namespace.getNamespaceDriver()) - .getLedgerAllocator(); - assertTrue(allocator instanceof LedgerAllocatorPool); - LedgerAllocatorPool allocatorPool = (LedgerAllocatorPool) allocator; - assertEquals(0, allocatorPool.obtainMapSize()); - - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - writer.write(DLMTestUtil.getLogRecordInstance(1L)); - Utils.close(writer); - } - - @Test - public void testLedgerNumber() throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - ensureURICreated(zkc, uri); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - - BKDistributedLogNamespace namespace = (BKDistributedLogNamespace) - NamespaceBuilder.newBuilder() - .conf(confLocal) - .uri(uri) - .build(); - DistributedLogManager dlm = namespace.openLog("test-log"); - BookKeeperAdmin admin = new BookKeeperAdmin(zkServers); - - Set s1 = getLedgers(admin); - LOG.info("Ledgers after init: " + s1); - - LogWriter writer = dlm.openLogWriter(); - writer.write(new LogRecord(1, "test-data".getBytes(StandardCharsets.UTF_8))); - writer.close(); - - Set s2 = getLedgers(admin); - LOG.info("Ledgers after write: " + s2); - dlm.delete(); - assertEquals(1, s2.size() - s1.size()); // exact 1 ledger created only - - Set s3 = getLedgers(admin); - LOG.info("Ledgers after delete: " + s3); - - assertEquals(s1.size(), s3.size()); - - } - - // Get all ledgers from BK admin - private Set getLedgers(BookKeeperAdmin bkAdmin) throws IOException { - Set res = new HashSet<>(); - bkAdmin.listLedgers().forEach(res::add); - return res; - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKSyncLogReader.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKSyncLogReader.java deleted file mode 100644 index fc1f70b966a..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestBKSyncLogReader.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.exceptions.LogNotFoundException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test Sync Log Reader. - */ -public class TestBKSyncLogReader extends TestDistributedLogBase { - - private static final Logger logger = LoggerFactory.getLogger(TestBKSyncLogReader.class); - - @Rule - public TestName testName = new TestName(); - - @Test(timeout = 60000) - public void testCreateReaderBeyondLastTransactionId() throws Exception { - String name = testName.getMethodName(); - DistributedLogManager dlm = createNewDLM(conf, name); - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 1; i < 10; i++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(i); - out.write(op); - } - out.closeAndComplete(); - - LogReader reader = dlm.getInputStream(20L); - assertNull(reader.readNext(false)); - - // write another 20 records - out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 10; i < 30; i++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(i); - out.write(op); - } - out.closeAndComplete(); - - for (int i = 0; i < 10; i++) { - LogRecord record = waitForNextRecord(reader); - assertEquals(20L + i, record.getTransactionId()); - } - assertNull(reader.readNext(false)); - } - - @Test(timeout = 60000) - public void testDeletingLogWhileReading() throws Exception { - String name = testName.getMethodName(); - DistributedLogManager dlm = createNewDLM(conf, name); - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 1; i < 10; i++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(i); - out.write(op); - } - out.closeAndComplete(); - - LogReader reader = dlm.getInputStream(1L); - for (int i = 1; i < 10; i++) { - LogRecord record = waitForNextRecord(reader); - assertEquals((long) i, record.getTransactionId()); - } - - DistributedLogManager deleteDLM = createNewDLM(conf, name); - deleteDLM.delete(); - - LogRecord record; - try { - record = reader.readNext(false); - while (null == record) { - record = reader.readNext(false); - } - fail("Should fail reading next with LogNotFound"); - } catch (LogNotFoundException lnfe) { - // expected - } - } - - @Test(timeout = 60000) - public void testReadingFromEmptyLog() throws Exception { - String name = testName.getMethodName(); - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(Integer.MAX_VALUE); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - // write a record but not commit - LogRecord op = DLMTestUtil.getLogRecordInstance(1L); - out.write(op); - - LogReader reader = dlm.getInputStream(1L); - assertNull(reader.readNext(true)); - assertNull(reader.readNext(false)); - - op = DLMTestUtil.getLogRecordInstance(2L); - out.write(op); - - // reader is able to read first record - LogRecord record = waitForNextRecord(reader); - assertNotNull(record); - assertEquals(1L, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - - assertNull(reader.readNext(true)); - - out.close(); - reader.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReadRecordsAfterReadAheadCaughtUp() throws Exception { - String name = testName.getMethodName(); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(Integer.MAX_VALUE); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 1L; i <= 10L; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(i); - out.write(record); - } - out.flush(); - out.commit(); - - logger.info("Write first 10 records"); - - // all 10 records are added to the stream - // then open a reader to read - BKSyncLogReader reader = (BKSyncLogReader) dlm.getInputStream(1L); - - // wait until readahead caught up - while (!reader.getReadAheadReader().isReadAheadCaughtUp()) { - TimeUnit.MILLISECONDS.sleep(20); - } - - logger.info("ReadAhead is caught up with first 10 records"); - - for (long i = 11L; i <= 20L; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(i); - out.write(record); - } - out.flush(); - out.commit(); - - logger.info("Write another 10 records"); - - // resume reading from sync reader util it consumes 20 records - long expectedTxId = 1L; - for (int i = 0; i < 20; i++) { - LogRecord record = reader.readNext(false); - while (null == record) { - record = reader.readNext(false); - } - assertEquals(expectedTxId, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - ++expectedTxId; - } - // after read 20 records, it should return null - assertNull(reader.readNext(false)); - - out.close(); - reader.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReadRecordsWhenReadAheadCatchingUp() throws Exception { - String name = testName.getMethodName(); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(Integer.MAX_VALUE); - confLocal.setReadAheadMaxRecords(1); - confLocal.setReadAheadBatchSize(1); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 1L; i <= 10L; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(i); - out.write(record); - } - out.flush(); - out.commit(); - - logger.info("Write first 10 records"); - - // open a reader to read - BKSyncLogReader reader = (BKSyncLogReader) dlm.getInputStream(1L); - // resume reading from sync reader. so it should be able to read all 10 records - // and return null to claim it as caughtup - LogRecord record = reader.readNext(false); - int numReads = 0; - long expectedTxId = 1L; - while (null != record) { - ++numReads; - assertEquals(expectedTxId, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - ++expectedTxId; - record = reader.readNext(false); - } - assertEquals(10, numReads); - - out.close(); - reader.close(); - dlm.close(); - } - - @Test(timeout = 60000) - public void testReadRecordsWhenReadAheadCatchingUp2() throws Exception { - String name = testName.getMethodName(); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(Integer.MAX_VALUE); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - final BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - for (long i = 1L; i <= 10L; i++) { - LogRecord record = DLMTestUtil.getLogRecordInstance(i); - out.write(record); - } - out.flush(); - out.commit(); - final AtomicLong nextTxId = new AtomicLong(11L); - - logger.info("Write first 10 records"); - - ScheduledExecutorService executorService = - Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - long txid = nextTxId.getAndIncrement(); - LogRecord record = DLMTestUtil.getLogRecordInstance(txid); - try { - out.write(record); - } catch (IOException e) { - // ignore the ioe - } - } - }, 0, 400, TimeUnit.MILLISECONDS); - - // open a reader to read - BKSyncLogReader reader = (BKSyncLogReader) dlm.getInputStream(1L); - // resume reading from sync reader. so it should be able to read all 10 records - // and return null to claim it as caughtup - LogRecord record = reader.readNext(false); - int numReads = 0; - long expectedTxId = 1L; - while (null != record) { - ++numReads; - assertEquals(expectedTxId, record.getTransactionId()); - DLMTestUtil.verifyLogRecord(record); - ++expectedTxId; - record = reader.readNext(false); - } - assertTrue(numReads >= 10); - - executorService.shutdown(); - out.close(); - reader.close(); - dlm.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestCancelledRead.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestCancelledRead.java deleted file mode 100644 index ae306b87cce..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestCancelledRead.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertNotNull; - -import java.util.concurrent.CompletableFuture; -import org.apache.distributedlog.api.LogWriter; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for RollLogSegments. - */ -public class TestCancelledRead extends TestDistributedLogBase { - private static final Logger logger = LoggerFactory.getLogger(TestRollLogSegments.class); - - @Test(timeout = 600000) - public void testWritingAndTailing() throws Exception { - String name = "writing-and-tailing"; - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setReadAheadWaitTime(5000) - .setOutputBufferSize(0) - .setCreateStreamIfNotExists(true) - .setImmediateFlushEnabled(true) - .setFailFastOnStreamNotReady(true) - .setPeriodicFlushFrequencyMilliSeconds(0) - .setLockTimeout(DistributedLogConstants.LOCK_IMMEDIATE) - .setEnableReadAhead(false) - .setLogSegmentRollingIntervalMinutes(0); - - CompletableFuture f = new CompletableFuture<>(); - long entryId = 0; - - try (BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(conf, name); - LogWriter writer = dlm.startLogSegmentNonPartitioned()) { - entryId++; - writer.write(DLMTestUtil.getLogRecordInstance(entryId, 100000)); - } - - try (BKDistributedLogManager dlmReader = (BKDistributedLogManager) createNewDLM(conf, name)) { - BKAsyncLogReader reader = (BKAsyncLogReader) dlmReader.getAsyncLogReader(DLSN.InitialDLSN); - - assertNotNull(reader.readNext().get()); - - conf.setMaxLogSegmentBytes(1000); - try (BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(conf, name); - LogWriter writer = dlm.startLogSegmentNonPartitioned()) { - for (int i = 0; i < 100; i++) { - entryId++; - writer.write(DLMTestUtil.getLogRecordInstance(entryId, 100)); - - assertNotNull(reader.readNext().get()); - } - } finally { - reader.asyncClose().get(); - } - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDLMTestUtil.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDLMTestUtil.java deleted file mode 100644 index 73d7d9df7c1..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDLMTestUtil.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import java.io.File; -import org.apache.bookkeeper.shims.zk.ZooKeeperServerShim; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Case for {@link LocalDLMEmulator}. - */ -public class TestDLMTestUtil { - static final Logger LOG = LoggerFactory.getLogger(TestDLMTestUtil.class); - - static { - // org.apache.zookeeper.test.ClientBase uses FourLetterWordMain, from 3.5.3 four letter words - // are disabled by default due to security reasons - System.setProperty("zookeeper.4lw.commands.whitelist", "*"); - } - - @Rule - public TestName testNames = new TestName(); - - @Test(timeout = 60000) - public void testRunZookeeperOnAnyPort() throws Exception { - Pair serverAndPort1 = null; - Pair serverAndPort2 = null; - Pair serverAndPort3 = null; - try { - File zkTmpDir1 = IOUtils.createTempDir("zookeeper1", "distrlog"); - serverAndPort1 = LocalDLMEmulator.runZookeeperOnAnyPort(7000, zkTmpDir1); - File zkTmpDir2 = IOUtils.createTempDir("zookeeper2", "distrlog"); - serverAndPort2 = LocalDLMEmulator.runZookeeperOnAnyPort(7000, zkTmpDir2); - File zkTmpDir3 = IOUtils.createTempDir("zookeeper3", "distrlog"); - serverAndPort3 = LocalDLMEmulator.runZookeeperOnAnyPort(7000, zkTmpDir3); - } catch (Exception ex) { - if (null != serverAndPort1) { - serverAndPort1.getLeft().stop(); - } - if (null != serverAndPort2) { - serverAndPort2.getLeft().stop(); - } - if (null != serverAndPort3) { - serverAndPort3.getLeft().stop(); - } - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogBase.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogBase.java deleted file mode 100644 index cbd135de894..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogBase.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertTrue; - -import com.google.common.base.Ticker; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.feature.SettableFeatureProvider; -import org.apache.bookkeeper.shims.zk.ZooKeeperServerShim; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.common.util.PermitLimiter; -import org.apache.distributedlog.common.util.SchedulerUtils; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.impl.logsegment.BKLogSegmentEntryWriter; -import org.apache.distributedlog.injector.AsyncFailureInjector; -import org.apache.distributedlog.injector.AsyncRandomFailureInjector; -import org.apache.distributedlog.io.AsyncCloseable; -import org.apache.distributedlog.logsegment.LogSegmentEntryWriter; -import org.apache.distributedlog.logsegment.LogSegmentMetadataCache; -import org.apache.distributedlog.logsegment.LogSegmentMetadataStore; -import org.apache.distributedlog.namespace.NamespaceDriver; -import org.apache.distributedlog.util.ConfUtils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.rules.Timeout; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * DistributedLogBase providing test environment setup for other Test Cases. - */ -public class TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestDistributedLogBase.class); - - @Rule - public Timeout globalTimeout = Timeout.seconds(120); - - static { - // org.apache.zookeeper.test.ClientBase uses FourLetterWordMain, from 3.5.3 four letter words - // are disabled by default due to security reasons - System.setProperty("zookeeper.4lw.commands.whitelist", "*"); - } - - protected static int numBookies = 3; - - // Num worker threads should be one, since the exec service is used for the ordered - // future pool in test cases, and setting to > 1 will therefore result in unordered - // write ops. - protected static DistributedLogConfiguration conf = - new DistributedLogConfiguration() - .setEnableReadAhead(true) - .setReadAheadMaxRecords(1000) - .setReadAheadBatchSize(10) - .setLockTimeout(1) - .setNumWorkerThreads(1) - .setReadAheadNoSuchLedgerExceptionOnReadLACErrorThresholdMillis(20) - .setSchedulerShutdownTimeoutMs(0) - .setLockTimeout(120) - .setZKSessionTimeoutSeconds(60) - .setDLLedgerMetadataLayoutVersion(LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - protected ZooKeeper zkc; - protected static LocalDLMEmulator bkutil; - protected static ZooKeeperServerShim zks; - protected static String zkServers; - protected static int zkPort; - protected static final List TMP_DIRS = new ArrayList(); - - @BeforeClass - public static void setupCluster() throws Exception { - setupCluster(numBookies); - } - - protected static void setupCluster(int nBookies) throws Exception { - File zkTmpDir = IOUtils.createTempDir("zookeeper", "distrlog"); - TMP_DIRS.add(zkTmpDir); - Pair serverAndPort = LocalDLMEmulator.runZookeeperOnAnyPort(zkTmpDir); - zks = serverAndPort.getLeft(); - zkPort = serverAndPort.getRight(); - bkutil = LocalDLMEmulator.newBuilder() - .numBookies(nBookies) - .zkHost("127.0.0.1") - .zkPort(zkPort) - .serverConf(DLMTestUtil.loadTestBkConf()) - .shouldStartZK(false) - .build(); - bkutil.start(); - zkServers = "127.0.0.1:" + zkPort; - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - LOG.warn("Uncaught exception at Thread {} : ", t.getName(), e); - } - }); - } - - @AfterClass - public static void teardownCluster() throws Exception { - bkutil.teardown(); - zks.stop(); - for (File dir : TMP_DIRS) { - FileUtils.forceDeleteOnExit(dir); - } - } - - @Before - public void setup() throws Exception { - try { - zkc = LocalDLMEmulator.connectZooKeeper("127.0.0.1", zkPort); - } catch (Exception ex) { - LOG.error("hit exception connecting to zookeeper at {}:{}", "127.0.0.1", zkPort, ex); - throw ex; - } - } - - @After - public void teardown() throws Exception { - if (null != zkc) { - zkc.close(); - } - } - - protected LogRecord waitForNextRecord(LogReader reader) throws Exception { - LogRecord record = reader.readNext(false); - while (null == record) { - record = reader.readNext(false); - } - return record; - } - - public URI createDLMURI(String path) throws Exception { - return DLMTestUtil.createDLMURI(zkPort, path); - } - - protected void ensureURICreated(URI uri) throws Exception { - ensureURICreated(zkc, uri); - } - - protected void ensureURICreated(ZooKeeper zkc, URI uri) throws Exception { - try { - zkc.create(uri.getPath(), new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } catch (KeeperException.NodeExistsException nee) { - // ignore - } - } - - public BKDistributedLogManager createNewDLM(DistributedLogConfiguration conf, - String name) throws Exception { - return createNewDLM(conf, name, PermitLimiter.NULL_PERMIT_LIMITER); - } - - public BKDistributedLogManager createNewDLM(DistributedLogConfiguration conf, - String name, - PermitLimiter writeLimiter) - throws Exception { - URI uri = createDLMURI("/" + name); - ensureURICreated(uri); - final Namespace namespace = NamespaceBuilder.newBuilder() - .uri(uri) - .conf(conf) - .build(); - final OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder() - .numThreads(1) - .name("test-scheduler") - .build(); - AsyncCloseable resourcesCloseable = new AsyncCloseable() { - @Override - public CompletableFuture asyncClose() { - LOG.info("Shutting down the scheduler"); - SchedulerUtils.shutdownScheduler(scheduler, 1, TimeUnit.SECONDS); - LOG.info("Shut down the scheduler"); - LOG.info("Closing the namespace"); - namespace.close(); - LOG.info("Closed the namespace"); - return FutureUtils.Void(); - } - }; - AsyncFailureInjector failureInjector = AsyncRandomFailureInjector.newBuilder() - .injectDelays(conf.getEIInjectReadAheadDelay(), - conf.getEIInjectReadAheadDelayPercent(), - conf.getEIInjectMaxReadAheadDelayMs()) - .injectErrors(false, 10) - .injectStops(conf.getEIInjectReadAheadStall(), 10) - .injectCorruption(conf.getEIInjectReadAheadBrokenEntries()) - .build(); - return new BKDistributedLogManager( - name, - conf, - ConfUtils.getConstDynConf(conf), - uri, - namespace.getNamespaceDriver(), - new LogSegmentMetadataCache(conf, Ticker.systemTicker()), - scheduler, - DistributedLogConstants.UNKNOWN_CLIENT_ID, - DistributedLogConstants.LOCAL_REGION_ID, - writeLimiter, - new SettableFeatureProvider("", 0), - failureInjector, - NullStatsLogger.INSTANCE, - NullStatsLogger.INSTANCE, - Optional.of(resourcesCloseable)); - } - - protected LogSegmentMetadataStore getLogSegmentMetadataStore(Namespace namespace) - throws IOException { - return namespace.getNamespaceDriver().getLogStreamMetadataStore(NamespaceDriver.Role.READER) - .getLogSegmentMetadataStore(); - } - - protected ZooKeeperClient getZooKeeperClient(Namespace namespace) throws Exception { - NamespaceDriver driver = namespace.getNamespaceDriver(); - assertTrue(driver instanceof BKNamespaceDriver); - return ((BKNamespaceDriver) driver).getWriterZKC(); - } - - @SuppressWarnings("deprecation") - protected BookKeeperClient getBookKeeperClient(Namespace namespace) throws Exception { - NamespaceDriver driver = namespace.getNamespaceDriver(); - assertTrue(driver instanceof BKNamespaceDriver); - return ((BKNamespaceDriver) driver).getReaderBKC(); - } - - protected LedgerHandle getLedgerHandle(BKLogSegmentWriter segmentWriter) { - LogSegmentEntryWriter entryWriter = segmentWriter.getEntryWriter(); - assertTrue(entryWriter instanceof BKLogSegmentEntryWriter); - return ((BKLogSegmentEntryWriter) entryWriter).getLedgerHandle(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogConfiguration.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogConfiguration.java deleted file mode 100644 index 4fbe4f5f7dd..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestDistributedLogConfiguration.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.List; -import java.util.Optional; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.apache.commons.configuration.StrictConfigurationComparator; -import org.apache.distributedlog.net.DNSResolverForRacks; -import org.apache.distributedlog.net.DNSResolverForRows; -import org.junit.Test; - - - -/** - * Test Cases for truncation. - */ -public class TestDistributedLogConfiguration { - - static final class TestDNSResolver implements DNSToSwitchMapping { - - public TestDNSResolver() {} - - @Override - public List resolve(List list) { - return list; - } - - @Override - public void reloadCachedMappings() { - // no-op - } - } - - @Test(timeout = 20000) - public void loadStreamConfGoodOverrideAccepted() throws Exception { - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - assertEquals(conf.getPeriodicFlushFrequencyMilliSeconds(), - DistributedLogConfiguration.BKDL_PERIODIC_FLUSH_FREQUENCY_MILLISECONDS_DEFAULT); - assertEquals(conf.getReaderIdleErrorThresholdMillis(), - DistributedLogConfiguration.BKDL_READER_IDLE_ERROR_THRESHOLD_MILLIS_DEFAULT); - DistributedLogConfiguration override = new DistributedLogConfiguration(); - override.setPeriodicFlushFrequencyMilliSeconds( - DistributedLogConfiguration.BKDL_PERIODIC_FLUSH_FREQUENCY_MILLISECONDS_DEFAULT + 1); - override.setReaderIdleErrorThresholdMillis( - DistributedLogConfiguration.BKDL_READER_IDLE_ERROR_THRESHOLD_MILLIS_DEFAULT - 1); - conf.loadStreamConf(Optional.of(override)); - assertEquals(conf.getPeriodicFlushFrequencyMilliSeconds(), - DistributedLogConfiguration.BKDL_PERIODIC_FLUSH_FREQUENCY_MILLISECONDS_DEFAULT + 1); - assertEquals(conf.getReaderIdleErrorThresholdMillis(), - DistributedLogConfiguration.BKDL_READER_IDLE_ERROR_THRESHOLD_MILLIS_DEFAULT - 1); - } - - @SuppressWarnings("deprecation") - @Test(timeout = 20000) - public void loadStreamConfBadOverrideIgnored() throws Exception { - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - assertEquals(conf.getBKClientWriteTimeout(), - DistributedLogConfiguration.BKDL_BKCLIENT_WRITE_TIMEOUT_DEFAULT); - DistributedLogConfiguration override = new DistributedLogConfiguration(); - override.setBKClientWriteTimeout( - DistributedLogConfiguration.BKDL_BKCLIENT_WRITE_TIMEOUT_DEFAULT + 1); - conf.loadStreamConf(Optional.of(override)); - assertEquals(conf.getBKClientWriteTimeout(), - DistributedLogConfiguration.BKDL_BKCLIENT_WRITE_TIMEOUT_DEFAULT); - } - - @Test(timeout = 20000) - public void loadStreamConfNullOverrides() throws Exception { - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - DistributedLogConfiguration confClone = new DistributedLogConfiguration(); - Optional streamConfiguration = Optional.empty(); - conf.loadStreamConf(streamConfiguration); - - StrictConfigurationComparator comp = new StrictConfigurationComparator(); - assertTrue(comp.compare(conf, confClone)); - } - - @Test(timeout = 200000) - public void getEnsemblePlacementResolverClass() throws Exception { - DistributedLogConfiguration conf1 = new DistributedLogConfiguration(); - assertEquals(DNSResolverForRacks.class, conf1.getEnsemblePlacementDnsResolverClass()); - DistributedLogConfiguration conf2 = new DistributedLogConfiguration() - .setRowAwareEnsemblePlacementEnabled(true); - assertEquals(DNSResolverForRows.class, conf2.getEnsemblePlacementDnsResolverClass()); - DistributedLogConfiguration conf3 = new DistributedLogConfiguration() - .setRowAwareEnsemblePlacementEnabled(true) - .setEnsemblePlacementDnsResolverClass(TestDNSResolver.class); - assertEquals(TestDNSResolver.class, conf3.getEnsemblePlacementDnsResolverClass()); - } - - @SuppressWarnings("deprecation") - @Test(timeout = 200000) - public void validateConfiguration(){ - boolean exceptionThrown = false; - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - // validate default configuration - conf.validate(); - // test equal, should not throw exception - conf.setReadLACLongPollTimeout(conf.getBKClientReadTimeout() * 1000); - try { - conf.validate(); - } catch (IllegalArgumentException e){ - exceptionThrown = true; - } - assertFalse(exceptionThrown); - // test invalid case, should throw exception - exceptionThrown = false; - conf.setReadLACLongPollTimeout(conf.getBKClientReadTimeout() * 1000 * 2); - try { - conf.validate(); - } catch (IllegalArgumentException e){ - exceptionThrown = true; - } - assertTrue(exceptionThrown); - } - - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntry.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntry.java deleted file mode 100644 index 5b2e7af35f9..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntry.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.distributedlog.EnvelopedEntry.HEADER_LENGTH; -import static org.apache.distributedlog.LogRecord.MAX_LOGRECORD_SIZE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import io.netty.util.ReferenceCountUtil; -import java.nio.ByteBuffer; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.common.concurrent.FutureEventListener; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.distributedlog.Entry.Reader; -import org.apache.distributedlog.Entry.Writer; -import org.apache.distributedlog.exceptions.LogRecordTooLongException; -import org.apache.distributedlog.io.CompressionCodec; -import org.apache.distributedlog.util.Utils; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test Case of {@link Entry}. - */ -public class TestEntry { - - @Test(timeout = 20000) - public void testEmptyRecordSet() throws Exception { - Writer writer = Entry.newEntry( - "test-empty-record-set", - 1024, - true, - CompressionCodec.Type.NONE); - assertEquals("zero bytes", HEADER_LENGTH, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - ByteBuf buffer = writer.getBuffer(); - EnvelopedEntryReader reader = (EnvelopedEntryReader) Entry.newBuilder() - .setEntry(buffer) - .setLogSegmentInfo(1L, 0L) - .setEntryId(0L) - .buildReader(); - int refCnt = reader.getSrcBuf().refCnt(); - assertFalse(reader.isExhausted()); - Assert.assertNull("Empty record set should return null", - reader.nextRecord()); - assertTrue(reader.isExhausted()); - assertEquals(refCnt - 1, reader.getSrcBuf().refCnt()); - - // read next record again (to test release buffer) - Assert.assertNull("Empty record set should return null", - reader.nextRecord()); - assertEquals(refCnt - 1, reader.getSrcBuf().refCnt()); - ReferenceCountUtil.release(buffer); - } - - @Test(timeout = 20000) - public void testWriteTooLongRecord() throws Exception { - Writer writer = Entry.newEntry( - "test-write-too-long-record", - 1024, - true, - CompressionCodec.Type.NONE); - assertEquals("zero bytes", HEADER_LENGTH, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - LogRecord largeRecord = new LogRecord(1L, new byte[MAX_LOGRECORD_SIZE + 1]); - try { - writer.writeRecord(largeRecord, new CompletableFuture()); - Assert.fail("Should fail on writing large record"); - } catch (LogRecordTooLongException lrtle) { - // expected - } - assertEquals("zero bytes", HEADER_LENGTH, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - ByteBuf buffer = writer.getBuffer(); - assertEquals("zero bytes", HEADER_LENGTH, buffer.readableBytes()); - ReferenceCountUtil.release(buffer); - } - - @Test(timeout = 20000) - public void testWriteRecords() throws Exception { - Writer writer = Entry.newEntry( - "test-write-records", - 1024, - true, - CompressionCodec.Type.NONE); - assertEquals("zero bytes", HEADER_LENGTH, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - List> writePromiseList = Lists.newArrayList(); - // write first 5 records - for (int i = 0; i < 5; i++) { - LogRecord record = new LogRecord(i, ("record-" + i).getBytes(UTF_8)); - record.setPositionWithinLogSegment(i); - CompletableFuture writePromise = new CompletableFuture(); - writer.writeRecord(record, writePromise); - writePromiseList.add(writePromise); - assertEquals((i + 1) + " records", (i + 1), writer.getNumRecords()); - } - - // write large record - LogRecord largeRecord = new LogRecord(1L, new byte[MAX_LOGRECORD_SIZE + 1]); - try { - writer.writeRecord(largeRecord, new CompletableFuture()); - Assert.fail("Should fail on writing large record"); - } catch (LogRecordTooLongException lrtle) { - // expected - } - assertEquals("5 records", 5, writer.getNumRecords()); - - // write another 5 records - for (int i = 0; i < 5; i++) { - LogRecord record = new LogRecord(i + 5, ("record-" + (i + 5)).getBytes(UTF_8)); - record.setPositionWithinLogSegment(i + 5); - CompletableFuture writePromise = new CompletableFuture(); - writer.writeRecord(record, writePromise); - writePromiseList.add(writePromise); - assertEquals((i + 6) + " records", (i + 6), writer.getNumRecords()); - } - - ByteBuf buffer = writer.getBuffer(); - buffer.retain(); - - // Test transmit complete - writer.completeTransmit(1L, 1L); - List writeResults = Utils.ioResult(FutureUtils.collect(writePromiseList)); - for (int i = 0; i < 10; i++) { - assertEquals(new DLSN(1L, 1L, i), writeResults.get(i)); - } - - // Test reading from buffer - Reader reader = Entry.newBuilder() - .setEntry(buffer) - .setLogSegmentInfo(1L, 1L) - .setEntryId(0L) - .setEnvelopeEntry(true) - .buildReader(); - ReferenceCountUtil.release(buffer); - LogRecordWithDLSN record = reader.nextRecord(); - int numReads = 0; - long expectedTxid = 0L; - while (null != record) { - assertEquals(expectedTxid, record.getTransactionId()); - assertEquals(expectedTxid, record.getSequenceId()); - assertEquals(new DLSN(1L, 0L, expectedTxid), record.getDlsn()); - ++numReads; - ++expectedTxid; - record = reader.nextRecord(); - } - assertEquals(10, numReads); - - reader.release(); - } - - @Test(timeout = 20000) - public void testWriteRecordSet() throws Exception { - Writer writer = Entry.newEntry( - "test-write-recordset", - 1024, - true, - CompressionCodec.Type.NONE); - assertEquals("zero bytes", HEADER_LENGTH, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - List> writePromiseList = Lists.newArrayList(); - // write first 5 records - for (int i = 0; i < 5; i++) { - LogRecord record = new LogRecord(i, ("record-" + i).getBytes(UTF_8)); - record.setPositionWithinLogSegment(i); - CompletableFuture writePromise = new CompletableFuture(); - writer.writeRecord(record, writePromise); - writePromiseList.add(writePromise); - assertEquals((i + 1) + " records", (i + 1), writer.getNumRecords()); - } - - final LogRecordSet.Writer recordSetWriter = LogRecordSet.newWriter(1024, CompressionCodec.Type.NONE); - List> recordSetPromiseList = Lists.newArrayList(); - // write another 5 records as a batch - for (int i = 0; i < 5; i++) { - ByteBuffer record = ByteBuffer.wrap(("record-" + (i + 5)).getBytes(UTF_8)); - CompletableFuture writePromise = new CompletableFuture(); - recordSetWriter.writeRecord(record, writePromise); - recordSetPromiseList.add(writePromise); - assertEquals((i + 1) + " records", (i + 1), recordSetWriter.getNumRecords()); - } - final ByteBuf recordSetBuffer = recordSetWriter.getBuffer(); - LogRecord setRecord = new LogRecord(5L, recordSetBuffer); - setRecord.setPositionWithinLogSegment(5); - setRecord.setRecordSet(); - CompletableFuture writePromise = new CompletableFuture(); - writePromise.whenComplete(new FutureEventListener() { - @Override - public void onSuccess(DLSN dlsn) { - recordSetWriter.completeTransmit( - dlsn.getLogSegmentSequenceNo(), - dlsn.getEntryId(), - dlsn.getSlotId()); - } - - @Override - public void onFailure(Throwable cause) { - recordSetWriter.abortTransmit(cause); - } - }); - writer.writeRecord(setRecord, writePromise); - writePromiseList.add(writePromise); - - // write last 5 records - for (int i = 0; i < 5; i++) { - LogRecord record = new LogRecord(i + 10, ("record-" + (i + 10)).getBytes(UTF_8)); - record.setPositionWithinLogSegment(i + 10); - writePromise = new CompletableFuture(); - writer.writeRecord(record, writePromise); - writePromiseList.add(writePromise); - assertEquals((i + 11) + " records", (i + 11), writer.getNumRecords()); - } - - ByteBuf buffer = writer.getBuffer(); - buffer.retain(); - - // Test transmit complete - writer.completeTransmit(1L, 1L); - List writeResults = Utils.ioResult(FutureUtils.collect(writePromiseList)); - for (int i = 0; i < 5; i++) { - assertEquals(new DLSN(1L, 1L, i), writeResults.get(i)); - } - assertEquals(new DLSN(1L, 1L, 5), writeResults.get(5)); - for (int i = 0; i < 5; i++) { - assertEquals(new DLSN(1L, 1L, (10 + i)), writeResults.get(6 + i)); - } - List recordSetWriteResults = Utils.ioResult(FutureUtils.collect(recordSetPromiseList)); - for (int i = 0; i < 5; i++) { - assertEquals(new DLSN(1L, 1L, (5 + i)), recordSetWriteResults.get(i)); - } - - // Test reading from buffer - verifyReadResult(buffer, 1L, 1L, 1L, true, - new DLSN(1L, 1L, 2L), 3, 5, 5, - new DLSN(1L, 1L, 2L), 2L); - verifyReadResult(buffer, 1L, 1L, 1L, true, - new DLSN(1L, 1L, 7L), 0, 3, 5, - new DLSN(1L, 1L, 7L), 7L); - verifyReadResult(buffer, 1L, 1L, 1L, true, - new DLSN(1L, 1L, 12L), 0, 0, 3, - new DLSN(1L, 1L, 12L), 12L); - verifyReadResult(buffer, 1L, 1L, 1L, false, - new DLSN(1L, 1L, 2L), 3, 5, 5, - new DLSN(1L, 1L, 2L), 2L); - verifyReadResult(buffer, 1L, 1L, 1L, false, - new DLSN(1L, 1L, 7L), 0, 3, 5, - new DLSN(1L, 1L, 7L), 7L); - verifyReadResult(buffer, 1L, 1L, 1L, false, - new DLSN(1L, 1L, 12L), 0, 0, 3, - new DLSN(1L, 1L, 12L), 12L); - - ReferenceCountUtil.release(buffer); - } - - void verifyReadResult(ByteBuf data, - long lssn, long entryId, long startSequenceId, - boolean deserializeRecordSet, - DLSN skipTo, - int firstNumRecords, - int secondNumRecords, - int lastNumRecords, - DLSN expectedDLSN, - long expectedTxId) throws Exception { - Reader reader = Entry.newBuilder() - .setEntry(data) - .setLogSegmentInfo(lssn, startSequenceId) - .setEntryId(entryId) - .deserializeRecordSet(deserializeRecordSet) - .buildReader(); - reader.skipTo(skipTo); - - LogRecordWithDLSN record; - for (int i = 0; i < firstNumRecords; i++) { // first - record = reader.nextRecord(); - assertNotNull(record); - assertEquals(expectedDLSN, record.getDlsn()); - assertEquals(expectedTxId, record.getTransactionId()); - assertNotNull("record " + record + " payload is null", - record.getPayloadBuf()); - assertEquals("record-" + expectedTxId, new String(record.getPayload(), UTF_8)); - expectedDLSN = expectedDLSN.getNextDLSN(); - ++expectedTxId; - } - - boolean verifyDeserializedRecords = true; - if (firstNumRecords > 0) { - verifyDeserializedRecords = deserializeRecordSet; - } - if (verifyDeserializedRecords) { - long txIdOfRecordSet = 5; - for (int i = 0; i < secondNumRecords; i++) { - record = reader.nextRecord(); - assertNotNull(record); - assertEquals(expectedDLSN, record.getDlsn()); - assertEquals(txIdOfRecordSet, record.getTransactionId()); - assertNotNull("record " + record + " payload is null", - record.getPayload()); - assertEquals("record-" + expectedTxId, new String(record.getPayload(), UTF_8)); - expectedDLSN = expectedDLSN.getNextDLSN(); - ++expectedTxId; - } - } else { - record = reader.nextRecord(); - assertNotNull(record); - assertEquals(expectedDLSN, record.getDlsn()); - assertEquals(expectedTxId, record.getTransactionId()); - for (int i = 0; i < secondNumRecords; i++) { - expectedDLSN = expectedDLSN.getNextDLSN(); - ++expectedTxId; - } - } - - for (int i = 0; i < lastNumRecords; i++) { - record = reader.nextRecord(); - assertNotNull(record); - assertEquals(expectedDLSN, record.getDlsn()); - assertEquals(expectedTxId, record.getTransactionId()); - assertNotNull("record " + record + " payload is null", - record.getPayload()); - assertEquals("record-" + expectedTxId, new String(record.getPayload(), UTF_8)); - expectedDLSN = expectedDLSN.getNextDLSN(); - ++expectedTxId; - } - - } - - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntryPosition.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntryPosition.java deleted file mode 100644 index d4319804aef..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestEntryPosition.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - - -/** - * Test Case for {@link EntryPosition}. - */ -public class TestEntryPosition { - - private void checkPosition(EntryPosition position, - long lssn, - long entryId) { - assertEquals(position.getLogSegmentSequenceNumber(), lssn); - assertEquals(position.getEntryId(), entryId); - } - - @Test - public void testAdvance() { - EntryPosition position = new EntryPosition(9L, 99L); - - checkPosition(position, 9L, 99L); - - // advance (8L, 100L) takes no effect - assertFalse(position.advance(8L, 100L)); - checkPosition(position, 9L, 99L); - // advance (9L, 98L) takes no effect - assertFalse(position.advance(9L, 98L)); - checkPosition(position, 9L, 99L); - // advance (9L, 99L) takes no effect - assertFalse(position.advance(9L, 99L)); - checkPosition(position, 9L, 99L); - // advance (9L, 100L) takes effects - assertTrue(position.advance(9L, 100L)); - checkPosition(position, 9L, 100L); - // advance (10L, 0L) takes effects - assertTrue(position.advance(10L, 0L)); - checkPosition(position, 10L, 0L); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestInterleavedReaders.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestInterleavedReaders.java deleted file mode 100644 index 059b06511f3..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestInterleavedReaders.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.util.Utils; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test Cases for InterleavedReaders. - */ -public class TestInterleavedReaders extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestInterleavedReaders.class); - - static { - conf.setOutputBufferSize(0); - conf.setImmediateFlushEnabled(true); - } - - private int drainStreams(LogReader reader0, int num0, LogReader reader1, int num1) - throws Exception { - // Allow time for watches to fire - Thread.sleep(15); - int numTrans = 0; - LogRecord record; - int i = 0; - while (i < num0) { - record = reader0.readNext(false); - if (null != record) { - assertTrue((record.getTransactionId() % 2 == 0)); - DLMTestUtil.verifyLogRecord(record); - numTrans++; - i++; - LOG.info("Read record {}", record); - } - } - i = 0; - while (i < num1) { - record = reader1.readNext(false); - if (null != record) { - assertTrue((record.getTransactionId() % 2 == 1)); - DLMTestUtil.verifyLogRecord(record); - numTrans++; - i++; - LOG.info("Read record {}", record); - } - } - return numTrans; - } - - @Test(timeout = 60000) - public void testInterleavedReaders() throws Exception { - String name = "distrlog-interleaved"; - BKDistributedLogManager dlmwrite0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmreader0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmwrite1 = createNewDLM(conf, name + "-1"); - BKDistributedLogManager dlmreader1 = createNewDLM(conf, name + "-1"); - - LogReader reader0 = null; - LogReader reader1 = null; - long txid = 1; - int numTrans = 0; - - BKAsyncLogWriter writer0 = dlmwrite0.startAsyncLogSegmentNonPartitioned(); - BKAsyncLogWriter writer1 = dlmwrite1.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 4; j++) { - for (int k = 1; k <= 10; k++) { - Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(txid++))); - Utils.ioResult(writer0.write(DLMTestUtil.getLogRecordInstance(txid++))); - } - Utils.ioResult(writer1.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - Utils.ioResult(writer0.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - if (null == reader0) { - reader0 = dlmreader0.getInputStream(1); - } - if (null == reader1) { - reader1 = dlmreader1.getInputStream(1); - } - numTrans += drainStreams(reader0, 10, reader1, 10); - assertEquals((txid - 1), numTrans); - } - reader0.close(); - reader1.close(); - dlmreader0.close(); - dlmwrite0.close(); - dlmreader1.close(); - dlmwrite1.close(); - } - - @Test(timeout = 60000) - public void testInterleavedReadersWithRollingEdge() throws Exception { - String name = "distrlog-interleaved-rolling-edge"; - BKDistributedLogManager dlmwrite0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmreader0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmwrite1 = createNewDLM(conf, name + "-1"); - BKDistributedLogManager dlmreader1 = createNewDLM(conf, name + "-1"); - - LogReader reader0 = null; - LogReader reader1 = null; - long txid = 1; - int numTrans = 0; - - BKAsyncLogWriter writer0 = dlmwrite0.startAsyncLogSegmentNonPartitioned(); - BKAsyncLogWriter writer1 = dlmwrite1.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 4; j++) { - if (j > 1) { - writer0.setForceRolling(true); - writer1.setForceRolling(true); - } - for (int k = 1; k <= 2; k++) { - Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(txid++))); - Utils.ioResult(writer0.write(DLMTestUtil.getLogRecordInstance(txid++))); - writer0.setForceRolling(false); - writer1.setForceRolling(false); - } - Utils.ioResult(writer1.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - Utils.ioResult(writer0.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - LOG.info("Completed {} write", j); - if (null == reader0) { - reader0 = dlmreader0.getInputStream(1); - } - if (null == reader1) { - reader1 = dlmreader1.getInputStream(1); - } - numTrans += drainStreams(reader0, 2, reader1, 2); - assertEquals((txid - 1), numTrans); - } - reader0.close(); - reader1.close(); - dlmreader0.close(); - dlmwrite0.close(); - dlmreader1.close(); - dlmwrite1.close(); - } - - @Test(timeout = 60000) - public void testInterleavedReadersWithRolling() throws Exception { - String name = "distrlog-interleaved-rolling"; - BKDistributedLogManager dlmwrite0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmreader0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmwrite1 = createNewDLM(conf, name + "-1"); - BKDistributedLogManager dlmreader1 = createNewDLM(conf, name + "-1"); - - LogReader reader0 = null; - LogReader reader1 = null; - long txid = 1; - int numTrans = 0; - - BKAsyncLogWriter writer0 = dlmwrite0.startAsyncLogSegmentNonPartitioned(); - BKAsyncLogWriter writer1 = dlmwrite1.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 2; j++) { - for (int k = 1; k <= 6; k++) { - if (k == 3) { - writer0.setForceRolling(true); - writer1.setForceRolling(true); - } - Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(txid++))); - Utils.ioResult(writer0.write(DLMTestUtil.getLogRecordInstance(txid++))); - writer0.setForceRolling(false); - writer1.setForceRolling(false); - } - Utils.ioResult(writer1.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - Utils.ioResult(writer0.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - if (null == reader0) { - reader0 = dlmreader0.getInputStream(1); - } - if (null == reader1) { - reader1 = dlmreader1.getInputStream(1); - } - numTrans += drainStreams(reader0, 6, reader1, 6); - assertEquals((txid - 1), numTrans); - } - reader0.close(); - reader1.close(); - dlmreader0.close(); - dlmwrite0.close(); - dlmreader1.close(); - dlmwrite1.close(); - } - - @Test(timeout = 60000) - public void testInterleavedReadersWithCleanup() throws Exception { - String name = "distrlog-interleaved-cleanup"; - BKDistributedLogManager dlmwrite0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmwrite1 = createNewDLM(conf, name + "-1"); - long txid = 1; - Long retentionPeriodOverride = null; - - BKAsyncLogWriter writer0 = dlmwrite0.startAsyncLogSegmentNonPartitioned(); - BKAsyncLogWriter writer1 = dlmwrite1.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 4; j++) { - for (int k = 1; k <= 10; k++) { - if (k == 5) { - writer0.setForceRolling(true); - writer0.overRideMinTimeStampToKeep(retentionPeriodOverride); - writer1.setForceRolling(true); - writer1.overRideMinTimeStampToKeep(retentionPeriodOverride); - } - DLSN dlsn1 = Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(txid++))); - LOG.info("writer1 write record {}", dlsn1); - DLSN dlsn0 = Utils.ioResult(writer0.write(DLMTestUtil.getLogRecordInstance(txid++))); - LOG.info("writer0 write record {}", dlsn0); - if (k == 5) { - writer0.setForceRolling(false); - writer1.setForceRolling(false); - retentionPeriodOverride = System.currentTimeMillis(); - } - Thread.sleep(5); - } - Utils.ioResult(writer1.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - Utils.ioResult(writer0.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - } - writer0.close(); - writer1.close(); - - DistributedLogManager dlmreader0 = createNewDLM(conf, name + "-0"); - DistributedLogManager dlmreader1 = createNewDLM(conf, name + "-1"); - LogReader reader0 = dlmreader0.getInputStream(1); - LogReader reader1 = dlmreader1.getInputStream(1); - int numTrans = drainStreams(reader0, 15, reader1, 15); - assertEquals(30, numTrans); - reader0.close(); - reader1.close(); - dlmreader0.close(); - dlmwrite0.close(); - dlmreader1.close(); - dlmwrite1.close(); - } - - @Test(timeout = 60000) - public void testInterleavedReadersWithRecovery() throws Exception { - String name = "distrlog-interleaved-recovery"; - BKDistributedLogManager dlmwrite0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmreader0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmwrite1 = createNewDLM(conf, name + "-1"); - BKDistributedLogManager dlmreader1 = createNewDLM(conf, name + "-1"); - - LogReader reader0 = null; - LogReader reader1 = null; - long txid = 1; - int numTrans = 0; - - BKAsyncLogWriter writer0 = dlmwrite0.startAsyncLogSegmentNonPartitioned(); - BKAsyncLogWriter writer1 = dlmwrite1.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 2; j++) { - for (int k = 1; k <= 6; k++) { - if (k == 3) { - writer0.setForceRecovery(true); - writer1.setForceRecovery(true); - } - DLSN dlsn1 = Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(txid++))); - LOG.info("writer1 write record {} - txid = {}", dlsn1, txid - 1); - DLSN dlsn0 = Utils.ioResult(writer0.write(DLMTestUtil.getLogRecordInstance(txid++))); - LOG.info("writer0 write record {} - txid = {}", dlsn0, txid - 1); - writer0.setForceRecovery(false); - writer1.setForceRecovery(false); - } - Utils.ioResult(writer1.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - Utils.ioResult(writer0.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - if (null == reader0) { - reader0 = dlmreader0.getInputStream(1); - } - if (null == reader1) { - reader1 = dlmreader1.getInputStream(1); - } - numTrans += drainStreams(reader0, 6, reader1, 6); - assertEquals((txid - 1), numTrans); - } - reader0.close(); - reader1.close(); - assertEquals(txid - 1, - dlmreader0.getLogRecordCount() + dlmreader1.getLogRecordCount()); - dlmreader0.close(); - dlmwrite0.close(); - dlmreader1.close(); - dlmwrite1.close(); - } - - @Test(timeout = 60000) - public void testInterleavedReadersWithRollingEdgeUnPartitioned() throws Exception { - String name = "distrlog-interleaved-rolling-edge-unpartitioned"; - BKDistributedLogManager dlmwrite0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmreader0 = createNewDLM(conf, name + "-0"); - BKDistributedLogManager dlmwrite1 = createNewDLM(conf, name + "-1"); - BKDistributedLogManager dlmreader1 = createNewDLM(conf, name + "-1"); - - LogReader reader0 = null; - LogReader reader1 = null; - long txid = 1; - int numTrans = 0; - - BKAsyncLogWriter writer0 = dlmwrite0.startAsyncLogSegmentNonPartitioned(); - BKAsyncLogWriter writer1 = dlmwrite1.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= 4; j++) { - if (j > 1) { - writer0.setForceRolling(true); - writer1.setForceRolling(true); - } - for (int k = 1; k <= 2; k++) { - Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(txid++))); - Utils.ioResult(writer0.write(DLMTestUtil.getLogRecordInstance(txid++))); - writer0.setForceRolling(false); - writer1.setForceRolling(false); - } - Utils.ioResult(writer1.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - Utils.ioResult(writer0.writeControlRecord(DLMTestUtil.getLogRecordInstance(txid - 1))); - if (null == reader0) { - reader0 = dlmreader0.getInputStream(1); - } - if (null == reader1) { - reader1 = dlmreader1.getInputStream(1); - } - numTrans += drainStreams(reader0, 2, reader1, 2); - assertEquals((txid - 1), numTrans); - } - reader0.close(); - reader1.close(); - dlmreader0.close(); - dlmreader1.close(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentCreation.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentCreation.java deleted file mode 100644 index 506e2539140..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentCreation.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.net.URI; -import java.util.List; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.util.Utils; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test Cases for LogSegmentCreation. - */ -public class TestLogSegmentCreation extends TestDistributedLogBase { - - static Logger LOG = LoggerFactory.getLogger(TestLogSegmentCreation.class); - - @Test(timeout = 60000) - public void testCreateLogSegmentAfterLoseLock() throws Exception { - URI uri = createDLMURI("/LogSegmentCreation"); - String name = "distrlog-createlogsegment-afterloselock"; - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setLockTimeout(99999) - .setOutputBufferSize(0) - .setImmediateFlushEnabled(true) - .setEnableLedgerAllocatorPool(true) - .setLedgerAllocatorPoolName("test"); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(conf).uri(uri).build(); - DistributedLogManager dlm = namespace.openLog(name); - final int numSegments = 3; - for (int i = 0; i < numSegments; i++) { - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - out.write(DLMTestUtil.getLogRecordInstance(i)); - out.closeAndComplete(); - } - - List segments = dlm.getLogSegments(); - LOG.info("Segments : {}", segments); - assertEquals(3, segments.size()); - - final DistributedLogManager dlm1 = namespace.openLog(name); - final DistributedLogManager dlm2 = namespace.openLog(name); - - BKAsyncLogWriter writer1 = (BKAsyncLogWriter) dlm1.startAsyncLogSegmentNonPartitioned(); - LOG.info("Created writer 1."); - BKSyncLogWriter writer2 = (BKSyncLogWriter) dlm2.startLogSegmentNonPartitioned(); - LOG.info("Created writer 2."); - writer2.write(DLMTestUtil.getLogRecordInstance(numSegments)); - writer2.closeAndComplete(); - - try { - Utils.ioResult(writer1.write(DLMTestUtil.getLogRecordInstance(numSegments + 1))); - fail("Should fail on writing new log records."); - } catch (Throwable t) { - LOG.error("Failed to write entry : ", t); - } - - segments = dlm.getLogSegments(); - - boolean hasInprogress = false; - boolean hasDuplicatedSegment = false; - long nextSeqNo = segments.get(0).getLogSegmentSequenceNumber(); - for (int i = 1; i < segments.size(); i++) { - LogSegmentMetadata segment = segments.get(i); - assertTrue(segment.getLogSegmentSequenceNumber() >= nextSeqNo); - if (segment.getLogSegmentSequenceNumber() == nextSeqNo) { - hasDuplicatedSegment = true; - } - nextSeqNo = segment.getLogSegmentSequenceNumber(); - if (segment.isInProgress()) { - hasInprogress = true; - } - } - assertEquals(4, segments.size()); - assertFalse(hasInprogress); - assertFalse(hasDuplicatedSegment); - - LOG.info("Segments : duplicated = {}, inprogress = {}, {}", - hasDuplicatedSegment, hasInprogress, segments); - - dlm1.close(); - dlm2.close(); - dlm.close(); - - namespace.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentMetadata.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentMetadata.java deleted file mode 100644 index 87b2b92b640..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentMetadata.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import org.apache.distributedlog.LogSegmentMetadata.LogSegmentMetadataBuilder; -import org.apache.distributedlog.LogSegmentMetadata.LogSegmentMetadataVersion; -import org.apache.distributedlog.LogSegmentMetadata.TruncationStatus; -import org.apache.distributedlog.exceptions.UnsupportedMetadataVersionException; -import org.apache.distributedlog.util.Utils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test {@link LogSegmentMetadata}. - */ -public class TestLogSegmentMetadata extends ZooKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestLogSegmentMetadata.class); - - static final int TEST_REGION_ID = 0xf - 1; - - private ZooKeeperClient zkc; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .zkServers(zkServers) - .build(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - } - - @Test(timeout = 60000) - public void testReadMetadata() throws Exception { - LogSegmentMetadata metadata1 = new LogSegmentMetadataBuilder("/metadata1", - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION, 1000, 1).setRegionId(TEST_REGION_ID).build(); - metadata1.write(zkc); - LogSegmentMetadata read1 = Utils.ioResult(LogSegmentMetadata.read(zkc, "/metadata1")); - assertEquals(metadata1, read1); - assertEquals(TEST_REGION_ID, read1.getRegionId()); - } - - @Test(timeout = 60000) - public void testReadMetadataCrossVersion() throws Exception { - LogSegmentMetadata metadata1 = new LogSegmentMetadataBuilder("/metadata2", - 1, 1000, 1).setRegionId(TEST_REGION_ID).build(); - metadata1.write(zkc); - // synchronous read - LogSegmentMetadata read1 = Utils.ioResult(LogSegmentMetadata.read(zkc, "/metadata2", true)); - assertEquals(read1.getLogSegmentId(), metadata1.getLogSegmentId()); - assertEquals(read1.getFirstTxId(), metadata1.getFirstTxId()); - assertEquals(read1.getLastTxId(), metadata1.getLastTxId()); - assertEquals(read1.getLogSegmentSequenceNumber(), metadata1.getLogSegmentSequenceNumber()); - assertEquals(DistributedLogConstants.LOCAL_REGION_ID, read1.getRegionId()); - } - - @Test(timeout = 60000) - public void testReadMetadataCrossVersionFailure() throws Exception { - LogSegmentMetadata metadata1 = new LogSegmentMetadataBuilder("/metadata-failure", - 1, 1000, 1).setRegionId(TEST_REGION_ID).build(); - metadata1.write(zkc); - // synchronous read - try { - LogSegmentMetadata read1 = Utils.ioResult(LogSegmentMetadata.read(zkc, "/metadata-failure")); - fail("The previous statement should throw an exception"); - } catch (UnsupportedMetadataVersionException e) { - // Expected - } - } - - - @Test(timeout = 60000) - public void testMutateTruncationStatus() { - LogSegmentMetadata metadata = - new LogSegmentMetadataBuilder( - "/metadata", LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES, 1L, 0L) - .setRegionId(0).setLogSegmentSequenceNo(1L).build(); - metadata = metadata.completeLogSegment("/completed-metadata", 1000L, 1000, 1000L, 0L, 0L); - - LogSegmentMetadata partiallyTruncatedSegment = - metadata.mutator() - .setTruncationStatus(TruncationStatus.PARTIALLY_TRUNCATED) - .setMinActiveDLSN(new DLSN(1L, 500L, 0L)) - .build(); - - LogSegmentMetadata fullyTruncatedSegment = - partiallyTruncatedSegment.mutator() - .setTruncationStatus(TruncationStatus.TRUNCATED) - .build(); - - assertEquals(new DLSN(1L, 500L, 0L), fullyTruncatedSegment.getMinActiveDLSN()); - } - - @Test(timeout = 60000) - public void testParseInvalidMetadata() throws Exception { - try { - LogSegmentMetadata.parseData("/metadata1", new byte[0], false); - fail("Should fail to parse invalid metadata"); - } catch (IOException ioe) { - // expected - } - } - - @Test(timeout = 60000) - public void testReadLogSegmentWithSequenceId() throws Exception { - LogSegmentMetadata metadata = - new LogSegmentMetadataBuilder( - "/metadata", LogSegmentMetadataVersion.VERSION_V5_SEQUENCE_ID, 1L, 0L) - .setRegionId(0) - .setLogSegmentSequenceNo(1L) - .setStartSequenceId(999L) - .build(); - // write inprogress log segment with v5 - String data = metadata.getFinalisedData(); - LogSegmentMetadata parsedMetadata = LogSegmentMetadata.parseData("/metadatav5", data.getBytes(UTF_8), false); - assertEquals(999L, parsedMetadata.getStartSequenceId()); - - LogSegmentMetadata metadatav4 = - new LogSegmentMetadataBuilder( - "/metadata", LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES, 1L, 0L) - .setRegionId(0) - .setLogSegmentSequenceNo(1L) - .setStartSequenceId(999L) - .build(); - String datav4 = metadatav4.getFinalisedData(); - LogSegmentMetadata parsedMetadatav4 = - LogSegmentMetadata.parseData("/metadatav4", datav4.getBytes(UTF_8), false); - assertTrue(parsedMetadatav4.getStartSequenceId() < 0); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentsZK.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentsZK.java deleted file mode 100644 index 5e1688f7c69..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestLogSegmentsZK.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import java.util.List; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.exceptions.DLIllegalStateException; -import org.apache.distributedlog.exceptions.UnexpectedException; -import org.apache.distributedlog.metadata.LogMetadata; -import org.apache.distributedlog.util.DLUtils; -import org.apache.zookeeper.data.Stat; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for LogSegmentsZK. - */ -public class TestLogSegmentsZK extends TestDistributedLogBase { - - static Logger LOG = LoggerFactory.getLogger(TestLogSegmentsZK.class); - - private static MaxLogSegmentSequenceNo getMaxLogSegmentSequenceNo(ZooKeeperClient zkc, URI uri, String streamName, - DistributedLogConfiguration conf) throws Exception { - Stat stat = new Stat(); - String logSegmentsPath = LogMetadata.getLogSegmentsPath( - uri, streamName, conf.getUnpartitionedStreamName()); - byte[] data = zkc.get().getData(logSegmentsPath, false, stat); - Versioned maxLSSNData = new Versioned(data, new LongVersion(stat.getVersion())); - return new MaxLogSegmentSequenceNo(maxLSSNData); - } - - private static void updateMaxLogSegmentSequenceNo(ZooKeeperClient zkc, URI uri, String streamName, - DistributedLogConfiguration conf, byte[] data) throws Exception { - String logSegmentsPath = LogMetadata.getLogSegmentsPath( - uri, streamName, conf.getUnpartitionedStreamName()); - zkc.get().setData(logSegmentsPath, data, -1); - } - - @Rule - public TestName testName = new TestName(); - - private URI createURI() throws Exception { - return createDLMURI("/" + testName.getMethodName()); - } - - /** - * Create Log Segment for an pre-create stream. No max ledger sequence number recorded. - */ - @Test(timeout = 60000) - public void testCreateLogSegmentOnPrecreatedStream() throws Exception { - URI uri = createURI(); - String streamName = testName.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setLockTimeout(99999) - .setOutputBufferSize(0) - .setImmediateFlushEnabled(true) - .setEnableLedgerAllocatorPool(true) - .setLedgerAllocatorPoolName("test"); - Namespace namespace = NamespaceBuilder.newBuilder().conf(conf).uri(uri).build(); - - namespace.createLog(streamName); - MaxLogSegmentSequenceNo max1 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf); - assertEquals(DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO, max1.getSequenceNumber()); - DistributedLogManager dlm = namespace.openLog(streamName); - final int numSegments = 3; - for (int i = 0; i < numSegments; i++) { - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - out.write(DLMTestUtil.getLogRecordInstance(i)); - out.closeAndComplete(); - } - MaxLogSegmentSequenceNo max2 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf); - assertEquals(3, max2.getSequenceNumber()); - dlm.close(); - namespace.close(); - } - - /** - * Create Log Segment when no max sequence number recorded in /ledgers. e.g. old version. - */ - @Test(timeout = 60000) - public void testCreateLogSegmentMissingMaxSequenceNumber() throws Exception { - URI uri = createURI(); - String streamName = testName.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setLockTimeout(99999) - .setOutputBufferSize(0) - .setImmediateFlushEnabled(true) - .setEnableLedgerAllocatorPool(true) - .setLedgerAllocatorPoolName("test"); - Namespace namespace = NamespaceBuilder.newBuilder().conf(conf).uri(uri).build(); - - namespace.createLog(streamName); - MaxLogSegmentSequenceNo max1 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf); - assertEquals(DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO, max1.getSequenceNumber()); - DistributedLogManager dlm = namespace.openLog(streamName); - final int numSegments = 3; - for (int i = 0; i < numSegments; i++) { - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - out.write(DLMTestUtil.getLogRecordInstance(i)); - out.closeAndComplete(); - } - MaxLogSegmentSequenceNo max2 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf); - assertEquals(3, max2.getSequenceNumber()); - - // nuke the max ledger sequence number - updateMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf, new byte[0]); - DistributedLogManager dlm1 = namespace.openLog(streamName); - try { - dlm1.startLogSegmentNonPartitioned(); - fail("Should fail with unexpected exceptions"); - } catch (UnexpectedException ue) { - // expected - } finally { - dlm1.close(); - } - - // invalid max ledger sequence number - updateMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), - uri, streamName, conf, "invalid-max".getBytes(UTF_8)); - DistributedLogManager dlm2 = namespace.openLog(streamName); - try { - dlm2.startLogSegmentNonPartitioned(); - fail("Should fail with unexpected exceptions"); - } catch (UnexpectedException ue) { - // expected - } finally { - dlm2.close(); - } - - dlm.close(); - namespace.close(); - } - - /** - * Create Log Segment while max sequence number isn't match with list of log segments. - */ - @Test(timeout = 60000) - public void testCreateLogSegmentUnmatchMaxSequenceNumber() throws Exception { - URI uri = createURI(); - String streamName = testName.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setLockTimeout(99999) - .setOutputBufferSize(0) - .setImmediateFlushEnabled(true) - .setEnableLedgerAllocatorPool(true) - .setLedgerAllocatorPoolName("test"); - Namespace namespace = NamespaceBuilder.newBuilder().conf(conf).uri(uri).build(); - - namespace.createLog(streamName); - MaxLogSegmentSequenceNo max1 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf); - assertEquals(DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO, max1.getSequenceNumber()); - DistributedLogManager dlm = namespace.openLog(streamName); - final int numSegments = 3; - for (int i = 0; i < numSegments; i++) { - BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - out.write(DLMTestUtil.getLogRecordInstance(i)); - out.closeAndComplete(); - } - MaxLogSegmentSequenceNo max2 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf); - assertEquals(3, max2.getSequenceNumber()); - - // update the max ledger sequence number - updateMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf, - DLUtils.serializeLogSegmentSequenceNumber(99)); - - DistributedLogManager dlm1 = namespace.openLog(streamName); - try { - BKSyncLogWriter out1 = (BKSyncLogWriter) dlm1.startLogSegmentNonPartitioned(); - out1.write(DLMTestUtil.getLogRecordInstance(numSegments + 1)); - out1.closeAndComplete(); - fail("Should fail creating new log segment when encountered unmatch max ledger sequence number"); - } catch (DLIllegalStateException lse) { - // expected - } finally { - dlm1.close(); - } - - DistributedLogManager dlm2 = namespace.openLog(streamName); - List segments = dlm2.getLogSegments(); - try { - assertEquals(3, segments.size()); - assertEquals(1L, segments.get(0).getLogSegmentSequenceNumber()); - assertEquals(2L, segments.get(1).getLogSegmentSequenceNumber()); - assertEquals(3L, segments.get(2).getLogSegmentSequenceNumber()); - } finally { - dlm2.close(); - } - - dlm.close(); - namespace.close(); - } - - @Test(timeout = 60000) - public void testCompleteLogSegmentConflicts() throws Exception { - URI uri = createURI(); - String streamName = testName.getMethodName(); - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setLockTimeout(99999) - .setOutputBufferSize(0) - .setImmediateFlushEnabled(true) - .setEnableLedgerAllocatorPool(true) - .setLedgerAllocatorPoolName("test"); - Namespace namespace = NamespaceBuilder.newBuilder().conf(conf).uri(uri).build(); - - namespace.createLog(streamName); - DistributedLogManager dlm1 = namespace.openLog(streamName); - DistributedLogManager dlm2 = namespace.openLog(streamName); - - // dlm1 is writing - BKSyncLogWriter out1 = (BKSyncLogWriter) dlm1.startLogSegmentNonPartitioned(); - out1.write(DLMTestUtil.getLogRecordInstance(1)); - // before out1 complete, out2 is in on recovery - // it completed the log segments which bump the version of /ledgers znode - BKAsyncLogWriter out2 = (BKAsyncLogWriter) dlm2.startAsyncLogSegmentNonPartitioned(); - - try { - out1.closeAndComplete(); - fail("Should fail closeAndComplete since other people already completed it."); - } catch (IOException ioe) { - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java deleted file mode 100644 index 8c89792445d..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - - -import static org.apache.distributedlog.NonBlockingReadsTestUtil.DEFAULT_SEGMENT_SIZE; -import static org.apache.distributedlog.NonBlockingReadsTestUtil.readNonBlocking; -import static org.apache.distributedlog.NonBlockingReadsTestUtil.writeRecordsForNonBlockingReads; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.exceptions.IdleReaderException; -import org.apache.distributedlog.util.Utils; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * {@link https://issues.apache.org/jira/browse/DL-12}. - */ -@Ignore -public class TestNonBlockingReads extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestNonBlockingReads.class); - - static { - conf.setOutputBufferSize(0); - conf.setImmediateFlushEnabled(true); - } - - @Test(timeout = 100000) - public void testNonBlockingRead() throws Exception { - String name = "distrlog-non-blocking-reader"; - final DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setReadAheadBatchSize(1); - confLocal.setReadAheadMaxRecords(1); - confLocal.setReaderIdleWarnThresholdMillis(100); - confLocal.setReadLACLongPollTimeout(49); - final DistributedLogManager dlm = createNewDLM(confLocal, name); - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - ScheduledFuture writerClosedFuture = null; - try { - final Thread currentThread = Thread.currentThread(); - writerClosedFuture = executor.schedule( - new Runnable() { - @Override - public void run() { - try { - writeRecordsForNonBlockingReads(confLocal, dlm, false); - } catch (Exception exc) { - currentThread.interrupt(); - } - - } - }, 100, TimeUnit.MILLISECONDS); - - readNonBlocking(dlm, false); - assertFalse(currentThread.isInterrupted()); - } finally { - if (writerClosedFuture != null){ - // ensure writer.closeAndComplete is done before we close dlm - writerClosedFuture.get(); - } - executor.shutdown(); - dlm.close(); - } - } - - @Test(timeout = 100000) - public void testNonBlockingReadRecovery() throws Exception { - String name = "distrlog-non-blocking-reader-recovery"; - final DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setReadAheadBatchSize(10); - confLocal.setReadAheadMaxRecords(10); - final DistributedLogManager dlm = createNewDLM(confLocal, name); - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - ScheduledFuture writerClosedFuture = null; - try { - final Thread currentThread = Thread.currentThread(); - writerClosedFuture = executor.schedule( - new Runnable() { - @Override - public void run() { - try { - writeRecordsForNonBlockingReads(confLocal, dlm, true); - } catch (Exception exc) { - currentThread.interrupt(); - } - - } - }, 100, TimeUnit.MILLISECONDS); - - - readNonBlocking(dlm, false); - assertFalse(currentThread.isInterrupted()); - } finally { - if (writerClosedFuture != null){ - // ensure writer.closeAndComplete is done before we close dlm - writerClosedFuture.get(); - } - executor.shutdown(); - dlm.close(); - } - } - - @Test(timeout = 100000) - public void testNonBlockingReadIdleError() throws Exception { - String name = "distrlog-non-blocking-reader-error"; - final DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setReadAheadBatchSize(1); - confLocal.setReadAheadMaxRecords(1); - confLocal.setReadLACLongPollTimeout(24); - confLocal.setReaderIdleWarnThresholdMillis(50); - confLocal.setReaderIdleErrorThresholdMillis(100); - final DistributedLogManager dlm = createNewDLM(confLocal, name); - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - ScheduledFuture writerClosedFuture = null; - try { - final Thread currentThread = Thread.currentThread(); - writerClosedFuture = executor.schedule( - new Runnable() { - @Override - public void run() { - try { - writeRecordsForNonBlockingReads(confLocal, dlm, false); - } catch (Exception exc) { - currentThread.interrupt(); - } - - } - }, 100, TimeUnit.MILLISECONDS); - - boolean exceptionEncountered = false; - try { - readNonBlocking(dlm, false, DEFAULT_SEGMENT_SIZE, true); - } catch (IdleReaderException exc) { - exceptionEncountered = true; - } - assertTrue(exceptionEncountered); - assertFalse(currentThread.isInterrupted()); - } finally { - if (writerClosedFuture != null){ - // ensure writer.closeAndComplete is done before we close dlm - writerClosedFuture.get(); - } - executor.shutdown(); - dlm.close(); - } - } - - @Test(timeout = 60000) - public void testNonBlockingReadAheadStall() throws Exception { - String name = "distrlog-non-blocking-reader-stall"; - final DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setReadAheadBatchSize(1); - confLocal.setReadAheadMaxRecords(3); - confLocal.setReadLACLongPollTimeout(249); - confLocal.setReaderIdleWarnThresholdMillis(500); - confLocal.setReaderIdleErrorThresholdMillis(30000); - final DistributedLogManager dlm = createNewDLM(confLocal, name); - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - ScheduledFuture writerClosedFuture = null; - try { - final Thread currentThread = Thread.currentThread(); - writerClosedFuture = executor.schedule( - new Runnable() { - @Override - public void run() { - try { - writeRecordsForNonBlockingReads(confLocal, dlm, false, 3); - } catch (Exception exc) { - currentThread.interrupt(); - } - - } - }, 10, TimeUnit.MILLISECONDS); - - boolean exceptionEncountered = false; - try { - readNonBlocking(dlm, false, 3, false); - } catch (IdleReaderException exc) { - LOG.info("Exception encountered", exc); - exceptionEncountered = true; - } - assertFalse(exceptionEncountered); - assertFalse(currentThread.isInterrupted()); - } finally { - if (writerClosedFuture != null){ - // ensure writer.closeAndComplete is done before we close dlm - writerClosedFuture.get(); - } - executor.shutdown(); - dlm.close(); - } - } - - private long createStreamWithInconsistentMetadata(String name) throws Exception { - DistributedLogManager dlm = createNewDLM(conf, name); - ZooKeeperClient zkClient = TestZooKeeperClientBuilder.newBuilder() - .uri(createDLMURI("/")) - .build(); - long txid = 1; - - long numRecordsWritten = 0; - int segmentSize = 10; - for (long i = 0; i < 3; i++) { - BKAsyncLogWriter out = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= segmentSize; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - Utils.ioResult(out.write(op)); - numRecordsWritten++; - } - out.closeAndComplete(); - } - - BKLogWriteHandler blplm = ((BKDistributedLogManager) (dlm)).createWriteHandler(true); - String completedZNode = blplm.completedLedgerZNode(txid - segmentSize, txid - 1, 3); - LogSegmentMetadata metadata = Utils.ioResult(LogSegmentMetadata.read(zkClient, completedZNode)); - zkClient.get().delete(completedZNode, -1); - LogSegmentMetadata metadataToChange = - metadata.mutator() - .setLastEntryId(metadata.getLastEntryId() + 100) - .setLastTxId(metadata.getLastTxId() + 100) - .build(); - metadataToChange.write(zkClient); - - txid += 100; - - - for (long i = 0; i < 3; i++) { - BKAsyncLogWriter out = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - for (long j = 1; j <= segmentSize; j++) { - LogRecord op = DLMTestUtil.getLogRecordInstance(txid++); - Utils.ioResult(out.write(op)); - numRecordsWritten++; - } - out.closeAndComplete(); - } - dlm.close(); - - return numRecordsWritten; - } - - @Test(timeout = 60000) - public void testHandleInconsistentMetadata() throws Exception { - String name = "distrlog-inconsistent-metadata-blocking-read"; - long numRecordsWritten = createStreamWithInconsistentMetadata(name); - - DistributedLogManager dlm = createNewDLM(conf, name); - try { - LogReader reader = dlm.getInputStream(45); - long numRecordsRead = 0; - LogRecord record = reader.readNext(false); - long lastTxId = -1; - while (numRecordsRead < numRecordsWritten / 2) { - if (null != record) { - DLMTestUtil.verifyLogRecord(record); - Assert.assertTrue(lastTxId < record.getTransactionId()); - lastTxId = record.getTransactionId(); - numRecordsRead++; - } else { - Thread.sleep(1); - } - record = reader.readNext(false); - } - reader.close(); - assertEquals(numRecordsWritten / 2, numRecordsRead); - } finally { - dlm.close(); - } - } - - @Test(timeout = 15000) - public void testHandleInconsistentMetadataNonBlocking() throws Exception { - String name = "distrlog-inconsistent-metadata-nonblocking-read"; - long numRecordsWritten = createStreamWithInconsistentMetadata(name); - - DistributedLogManager dlm = createNewDLM(conf, name); - try { - LogReader reader = dlm.getInputStream(45); - long numRecordsRead = 0; - long lastTxId = -1; - while (numRecordsRead < (numRecordsWritten / 2)) { - LogRecord record = reader.readNext(false); - if (record != null) { - DLMTestUtil.verifyLogRecord(record); - Assert.assertTrue(lastTxId < record.getTransactionId()); - lastTxId = record.getTransactionId(); - numRecordsRead++; - } else { - Thread.sleep(1); - } - } - reader.close(); - } finally { - dlm.close(); - } - } - - @Test(timeout = 15000) - public void testHandleInconsistentMetadataDLSNNonBlocking() throws Exception { - String name = "distrlog-inconsistent-metadata-nonblocking-read-dlsn"; - long numRecordsWritten = createStreamWithInconsistentMetadata(name); - - DistributedLogManager dlm = createNewDLM(conf, name); - try { - LogReader reader = dlm.getInputStream(DLSN.InitialDLSN); - long numRecordsRead = 0; - long lastTxId = -1; - while (numRecordsRead < numRecordsWritten) { - LogRecord record = reader.readNext(false); - if (record != null) { - DLMTestUtil.verifyLogRecord(record); - Assert.assertTrue(lastTxId < record.getTransactionId()); - lastTxId = record.getTransactionId(); - numRecordsRead++; - } else { - Thread.sleep(1); - } - } - reader.close(); - } finally { - dlm.close(); - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReadsMultiReader.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReadsMultiReader.java deleted file mode 100644 index a90301d53e3..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReadsMultiReader.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; - -import com.google.common.util.concurrent.RateLimiter; -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.exceptions.DLInterruptedException; -import org.apache.distributedlog.util.Utils; -import org.junit.Test; - - -/** - * Test Cases for NonBlockingReadsMultiReader. - */ -public class TestNonBlockingReadsMultiReader extends TestDistributedLogBase { - - static class ReaderThread extends Thread { - - final LogReader reader; - final boolean nonBlockReading; - volatile boolean running = true; - final AtomicInteger readCount = new AtomicInteger(0); - - ReaderThread(String name, LogReader reader, boolean nonBlockReading) { - super(name); - this.reader = reader; - this.nonBlockReading = nonBlockReading; - } - - @Override - public void run() { - while (running) { - try { - LogRecord r = reader.readNext(nonBlockReading); - if (r != null) { - readCount.incrementAndGet(); - if (readCount.get() % 1000 == 0) { - LOG.info("{} reading {}", getName(), r.getTransactionId()); - } - } - } catch (DLInterruptedException die) { - Thread.currentThread().interrupt(); - } catch (IOException e) { - break; - } - } - } - - void stopReading() { - LOG.info("Stopping reader."); - running = false; - interrupt(); - try { - join(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.error("Interrupted on waiting reader thread {} exiting : ", getName(), e); - } - } - - int getReadCount() { - return readCount.get(); - } - - } - - @Test(timeout = 60000) - public void testMultiReaders() throws Exception { - String name = "distrlog-multireaders"; - final RateLimiter limiter = RateLimiter.create(1000); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setOutputBufferSize(0); - confLocal.setImmediateFlushEnabled(true); - - DistributedLogManager dlmwrite = createNewDLM(confLocal, name); - - final AsyncLogWriter writer = dlmwrite.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(0))); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(1))); - final AtomicInteger writeCount = new AtomicInteger(2); - - DistributedLogManager dlmread = createNewDLM(conf, name); - - BKSyncLogReader reader0 = (BKSyncLogReader) dlmread.getInputStream(0); - - try { - ReaderThread[] readerThreads = new ReaderThread[1]; - readerThreads[0] = new ReaderThread("reader0-non-blocking", reader0, false); - // readerThreads[1] = new ReaderThread("reader1-non-blocking", reader0, false); - - final AtomicBoolean running = new AtomicBoolean(true); - Thread writerThread = new Thread("WriteThread") { - @Override - public void run() { - try { - long txid = 2; - DLSN dlsn = DLSN.InvalidDLSN; - while (running.get()) { - limiter.acquire(); - long curTxId = txid++; - dlsn = Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(curTxId))); - writeCount.incrementAndGet(); - if (curTxId % 1000 == 0) { - LOG.info("writer write {}", curTxId); - } - } - LOG.info("Completed writing record at {}", dlsn); - Utils.close(writer); - } catch (DLInterruptedException die) { - Thread.currentThread().interrupt(); - } catch (Exception e) { - - } - } - }; - - for (ReaderThread rt : readerThreads) { - rt.start(); - } - - writerThread.start(); - - TimeUnit.SECONDS.sleep(5); - - LOG.info("Stopping writer"); - - running.set(false); - writerThread.join(); - - LOG.info("Writer stopped after writing {} records, waiting for reader to complete", - writeCount.get()); - while (writeCount.get() > (readerThreads[0].getReadCount())) { - LOG.info("Write Count = {}, Read Count = {}", - new Object[] { writeCount.get(), readerThreads[0].getReadCount() }); - TimeUnit.MILLISECONDS.sleep(100); - } - assertEquals(writeCount.get(), - (readerThreads[0].getReadCount())); - - for (ReaderThread readerThread : readerThreads) { - readerThread.stopReading(); - } - } finally { - dlmwrite.close(); - reader0.close(); - dlmread.close(); - } - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadAheadEntryReader.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadAheadEntryReader.java deleted file mode 100644 index 6cb1e5d5f5f..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadAheadEntryReader.java +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.base.Ticker; -import com.google.common.collect.Lists; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stats.AlertStatsLogger; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.exceptions.AlreadyTruncatedTransactionException; -import org.apache.distributedlog.exceptions.DLIllegalStateException; -import org.apache.distributedlog.impl.logsegment.BKLogSegmentEntryStore; -import org.apache.distributedlog.injector.AsyncFailureInjector; -import org.apache.distributedlog.logsegment.LogSegmentEntryStore; -import org.apache.distributedlog.util.ConfUtils; -import org.apache.distributedlog.util.Utils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - - -/** - * Test Case {@link ReadAheadEntryReader}. - */ -public class TestReadAheadEntryReader extends TestDistributedLogBase { - - private static final int MAX_CACHED_ENTRIES = 5; - private static final int NUM_PREFETCH_ENTRIES = 10; - - @Rule - public TestName runtime = new TestName(); - private DistributedLogConfiguration baseConf; - private OrderedScheduler scheduler; - private BookKeeperClient bkc; - private ZooKeeperClient zkc; - - @Override - @Before - public void setup() throws Exception { - super.setup(); - baseConf = new DistributedLogConfiguration(); - baseConf.addConfiguration(conf); - baseConf.setOutputBufferSize(0); - baseConf.setPeriodicFlushFrequencyMilliSeconds(0); - baseConf.setImmediateFlushEnabled(false); - baseConf.setReadAheadMaxRecords(MAX_CACHED_ENTRIES); - baseConf.setNumPrefetchEntriesPerLogSegment(NUM_PREFETCH_ENTRIES); - baseConf.setMaxPrefetchEntriesPerLogSegment(NUM_PREFETCH_ENTRIES); - zkc = ZooKeeperClientBuilder.newBuilder() - .name("test-zk") - .zkServers(bkutil.getZkServers()) - .sessionTimeoutMs(conf.getZKSessionTimeoutMilliseconds()) - .zkAclId(conf.getZkAclId()) - .build(); - bkc = BookKeeperClientBuilder.newBuilder() - .name("test-bk") - .dlConfig(conf) - .ledgersPath("/ledgers") - .zkServers(bkutil.getZkServers()) - .build(); - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-read-ahead-entry-reader") - .numThreads(1) - .build(); - } - - @Override - @After - public void teardown() throws Exception { - if (null != bkc) { - bkc.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - if (null != zkc) { - zkc.close(); - } - super.teardown(); - } - - private ReadAheadEntryReader createEntryReader(String streamName, - DLSN fromDLSN, - BKDistributedLogManager dlm, - DistributedLogConfiguration conf) - throws Exception { - BKLogReadHandler readHandler = dlm.createReadHandler( - Optional.empty(), - true); - LogSegmentEntryStore entryStore = new BKLogSegmentEntryStore( - conf, - ConfUtils.getConstDynConf(conf), - zkc, - bkc, - scheduler, - null, - NullStatsLogger.INSTANCE, - AsyncFailureInjector.NULL); - return new ReadAheadEntryReader( - streamName, - fromDLSN, - conf, - readHandler, - entryStore, - scheduler, - Ticker.systemTicker(), - new AlertStatsLogger(NullStatsLogger.INSTANCE, "test-alert")); - } - - private void ensureOrderSchedulerEmpty(String streamName) throws Exception { - final CompletableFuture promise = new CompletableFuture(); - scheduler.executeOrdered(streamName, () -> { - FutureUtils.complete(promise, null); - }); - Utils.ioResult(promise); - } - - void generateCompletedLogSegments(DistributedLogManager dlm, - long numCompletedSegments, - long segmentSize) throws Exception { - generateCompletedLogSegments(dlm, numCompletedSegments, segmentSize, 1L); - } - - void generateCompletedLogSegments(DistributedLogManager dlm, - long numCompletedSegments, - long segmentSize, - long startTxId) throws Exception { - - long txid = startTxId; - for (long i = 0; i < numCompletedSegments; i++) { - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - for (long j = 1; j <= segmentSize; j++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid++))); - LogRecord ctrlRecord = DLMTestUtil.getLogRecordInstance(txid); - ctrlRecord.setControl(); - Utils.ioResult(writer.write(ctrlRecord)); - } - Utils.close(writer); - } - } - - AsyncLogWriter createInprogressLogSegment(DistributedLogManager dlm, - DistributedLogConfiguration conf, - long segmentSize) throws Exception { - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - for (long i = 1L; i <= segmentSize; i++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(i))); - LogRecord ctrlRecord = DLMTestUtil.getLogRecordInstance(i); - ctrlRecord.setControl(); - Utils.ioResult(writer.write(ctrlRecord)); - } - return writer; - } - - void expectAlreadyTruncatedTransactionException(ReadAheadEntryReader reader, - String errMsg) - throws Exception { - try { - reader.checkLastException(); - fail(errMsg); - } catch (AlreadyTruncatedTransactionException atte) { - // expected - } - } - - void expectIllegalStateException(ReadAheadEntryReader reader, - String errMsg) - throws Exception { - try { - reader.checkLastException(); - fail(errMsg); - } catch (DLIllegalStateException le) { - // expected - } - } - - void expectNoException(ReadAheadEntryReader reader) throws Exception { - reader.checkLastException(); - } - - // - // Test Positioning - // - - @Test(timeout = 60000) - public void testStartWithEmptySegmentList() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager dlm = createNewDLM(baseConf, streamName); - ReadAheadEntryReader readAheadEntryReader = - createEntryReader(streamName, DLSN.InitialDLSN, dlm, baseConf); - - readAheadEntryReader.start(Lists.newArrayList()); - - ensureOrderSchedulerEmpty(streamName); - assertFalse("ReadAhead should not be initialized with empty segment list", - readAheadEntryReader.isInitialized()); - assertTrue("ReadAhead should be empty when it isn't initialized", - readAheadEntryReader.isCacheEmpty()); - assertFalse("ReadAhead should not be marked as caught up when it isn't initialized", - readAheadEntryReader.isReadAheadCaughtUp()); - - // generate list of log segments - generateCompletedLogSegments(dlm, 1, MAX_CACHED_ENTRIES / 2 + 1); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - // notify the readahead reader with new segment lsit - readAheadEntryReader.onSegmentsUpdated(segments); - - // check the reader state after initialization - ensureOrderSchedulerEmpty(streamName); - assertTrue("ReadAhead should be initialized with non-empty segment list", - readAheadEntryReader.isInitialized()); - assertNotNull("current segment reader should be initialized", - readAheadEntryReader.getCurrentSegmentReader()); - assertEquals("current segment sequence number should be " + segments.get(0).getLogSegmentSequenceNumber(), - segments.get(0).getLogSegmentSequenceNumber(), readAheadEntryReader.getCurrentSegmentSequenceNumber()); - assertNull("there should be no next segment reader", - readAheadEntryReader.getNextSegmentReader()); - assertTrue("there should be no remaining segment readers", - readAheadEntryReader.getSegmentReaders().isEmpty()); - - Utils.close(readAheadEntryReader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testInitializeMultipleClosedLogSegments0() throws Exception { - // 5 completed log segments, start from the begin - testInitializeMultipleClosedLogSegments(5, DLSN.InitialDLSN, 0); - } - - @Test(timeout = 60000) - public void testInitializeMultipleClosedLogSegments1() throws Exception { - // 5 completed log segments, start from the 4th segment and it should skip first 3 log segments - testInitializeMultipleClosedLogSegments(5, new DLSN(4L, 0L, 0L), 3); - } - - private void testInitializeMultipleClosedLogSegments( - int numLogSegments, - DLSN fromDLSN, - int expectedCurrentSegmentIdx - ) throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager dlm = createNewDLM(baseConf, streamName); - - // generate list of log segments - generateCompletedLogSegments(dlm, 1, MAX_CACHED_ENTRIES / 2 + 1, 1L); - generateCompletedLogSegments(dlm, numLogSegments - 1, 1, MAX_CACHED_ENTRIES + 2); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be " + numLogSegments, - numLogSegments, segments.size()); - - ReadAheadEntryReader readAheadEntryReader = - createEntryReader(streamName, fromDLSN, dlm, baseConf); - readAheadEntryReader.start(segments); - - ensureOrderSchedulerEmpty(streamName); - assertTrue("ReadAhead should be initialized with non-empty segment list", - readAheadEntryReader.isInitialized()); - assertNotNull("current segment reader should be initialized", - readAheadEntryReader.getCurrentSegmentReader()); - assertTrue("current segment reader should be open and started", - readAheadEntryReader.getCurrentSegmentReader().isReaderOpen() - && readAheadEntryReader.getCurrentSegmentReader().isReaderStarted()); - assertEquals("current segment reader should read " + segments.get(expectedCurrentSegmentIdx), - segments.get(expectedCurrentSegmentIdx), - readAheadEntryReader.getCurrentSegmentReader().getSegment()); - assertEquals("current segment sequence number should be " - + segments.get(expectedCurrentSegmentIdx).getLogSegmentSequenceNumber(), - segments.get(expectedCurrentSegmentIdx).getLogSegmentSequenceNumber(), - readAheadEntryReader.getCurrentSegmentSequenceNumber()); - assertNull("next segment reader should not be initialized since it is a closed log segment", - readAheadEntryReader.getNextSegmentReader()); - assertEquals("there should be " + (numLogSegments - (expectedCurrentSegmentIdx + 1)) - + " remaining segment readers", - numLogSegments - (expectedCurrentSegmentIdx + 1), - readAheadEntryReader.getSegmentReaders().size()); - int segmentIdx = expectedCurrentSegmentIdx + 1; - for (ReadAheadEntryReader.SegmentReader reader : readAheadEntryReader.getSegmentReaders()) { - LogSegmentMetadata expectedSegment = segments.get(segmentIdx); - assertEquals("Segment should " + expectedSegment, - expectedSegment, reader.getSegment()); - assertTrue("Segment reader for " + expectedSegment + " should be open", - reader.isReaderOpen()); - assertFalse("Segment reader for " + expectedSegment + " should not be started", - reader.isReaderStarted()); - ++segmentIdx; - } - - Utils.close(readAheadEntryReader); - dlm.close(); - } - - @Test(timeout = 60000) - public void testPositioningAtInvalidLogSegment() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager dlm = createNewDLM(baseConf, streamName); - - // generate list of log segments - generateCompletedLogSegments(dlm, 3, 3); - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - Utils.ioResult(writer.truncate(new DLSN(2L, 1L, 0L))); - - List segments = dlm.getLogSegments(); - - // positioning on a truncated log segment (segment 1) - ReadAheadEntryReader readAheadEntryReader = - createEntryReader(streamName, DLSN.InitialDLSN, dlm, baseConf); - readAheadEntryReader.start(segments); - // ensure initialization to complete - ensureOrderSchedulerEmpty(streamName); - expectNoException(readAheadEntryReader); - Entry.Reader entryReader = - readAheadEntryReader.getNextReadAheadEntry(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - assertEquals(2L, entryReader.getLSSN()); - assertEquals(1L, entryReader.getEntryId()); - entryReader.release(); - Utils.close(readAheadEntryReader); - - // positioning on a partially truncated log segment (segment 2) before min active dlsn - readAheadEntryReader = createEntryReader(streamName, new DLSN(2L, 0L, 0L), dlm, baseConf); - readAheadEntryReader.start(segments); - // ensure initialization to complete - ensureOrderSchedulerEmpty(streamName); - expectNoException(readAheadEntryReader); - entryReader = - readAheadEntryReader.getNextReadAheadEntry(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - assertEquals(2L, entryReader.getLSSN()); - assertEquals(1L, entryReader.getEntryId()); - entryReader.release(); - Utils.close(readAheadEntryReader); - - // positioning on a partially truncated log segment (segment 2) after min active dlsn - readAheadEntryReader = createEntryReader(streamName, new DLSN(2L, 2L, 0L), dlm, baseConf); - readAheadEntryReader.start(segments); - // ensure initialization to complete - ensureOrderSchedulerEmpty(streamName); - expectNoException(readAheadEntryReader); - entryReader = - readAheadEntryReader.getNextReadAheadEntry(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - assertEquals(2L, entryReader.getLSSN()); - assertEquals(2L, entryReader.getEntryId()); - entryReader.release(); - Utils.close(readAheadEntryReader); - - Utils.close(writer); - dlm.close(); - } - - @Test(timeout = 60000) - public void testPositioningIgnoreTruncationStatus() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(baseConf); - confLocal.setIgnoreTruncationStatus(true); - - String streamName = runtime.getMethodName(); - BKDistributedLogManager dlm = createNewDLM(confLocal, streamName); - - // generate list of log segments - generateCompletedLogSegments(dlm, 3, 2); - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - Utils.ioResult(writer.truncate(new DLSN(2L, 1L, 0L))); - - List segments = dlm.getLogSegments(); - - // positioning on a truncated log segment (segment 1) - ReadAheadEntryReader readAheadEntryReader = - createEntryReader(streamName, DLSN.InitialDLSN, dlm, confLocal); - readAheadEntryReader.start(segments); - // ensure initialization to complete - ensureOrderSchedulerEmpty(streamName); - expectNoException(readAheadEntryReader); - Utils.close(readAheadEntryReader); - - // positioning on a partially truncated log segment (segment 2) before min active dlsn - readAheadEntryReader = createEntryReader(streamName, new DLSN(2L, 0L, 0L), dlm, confLocal); - readAheadEntryReader.start(segments); - // ensure initialization to complete - ensureOrderSchedulerEmpty(streamName); - expectNoException(readAheadEntryReader); - Utils.close(readAheadEntryReader); - - // positioning on a partially truncated log segment (segment 2) after min active dlsn - readAheadEntryReader = createEntryReader(streamName, new DLSN(2L, 1L, 0L), dlm, confLocal); - readAheadEntryReader.start(segments); - // ensure initialization to complete - ensureOrderSchedulerEmpty(streamName); - expectNoException(readAheadEntryReader); - Utils.close(readAheadEntryReader); - - Utils.close(writer); - dlm.close(); - } - - // - // Test Reinitialization - // - - @Test(timeout = 60000) - public void testLogSegmentSequenceNumberGap() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager dlm = createNewDLM(baseConf, streamName); - - // generate list of log segments - generateCompletedLogSegments(dlm, 3, 2); - List segments = dlm.getLogSegments(); - - ReadAheadEntryReader readAheadEntryReader = - createEntryReader(streamName, DLSN.InitialDLSN, dlm, baseConf); - readAheadEntryReader.start(segments.subList(0, 1)); - int expectedCurrentSegmentIdx = 0; - ensureOrderSchedulerEmpty(streamName); - assertTrue("ReadAhead should be initialized with non-empty segment list", - readAheadEntryReader.isInitialized()); - assertNotNull("current segment reader should be initialized", - readAheadEntryReader.getCurrentSegmentReader()); - assertTrue("current segment reader should be open and started", - readAheadEntryReader.getCurrentSegmentReader().isReaderOpen() - && readAheadEntryReader.getCurrentSegmentReader().isReaderStarted()); - assertEquals("current segment reader should read " + segments.get(expectedCurrentSegmentIdx), - segments.get(expectedCurrentSegmentIdx), - readAheadEntryReader.getCurrentSegmentReader().getSegment()); - assertEquals("current segment sequence number should be " - + segments.get(expectedCurrentSegmentIdx).getLogSegmentSequenceNumber(), - segments.get(expectedCurrentSegmentIdx).getLogSegmentSequenceNumber(), - readAheadEntryReader.getCurrentSegmentSequenceNumber()); - assertNull("next segment reader should not be initialized since it is a closed log segment", - readAheadEntryReader.getNextSegmentReader()); - - readAheadEntryReader.onSegmentsUpdated(segments.subList(2, 3)); - ensureOrderSchedulerEmpty(streamName); - expectIllegalStateException(readAheadEntryReader, - "inconsistent log segment found"); - - Utils.close(readAheadEntryReader); - dlm.close(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadUtils.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadUtils.java deleted file mode 100644 index 3fbcd700cf0..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReadUtils.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.logsegment.LogSegmentFilter; -import org.apache.distributedlog.util.Utils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Test {@link ReadUtils}. - */ -public class TestReadUtils extends TestDistributedLogBase { - - static final Logger LOG = LoggerFactory.getLogger(TestReadUtils.class); - - @Rule - public TestName runtime = new TestName(); - - private CompletableFuture> getLogRecordNotLessThanTxId( - BKDistributedLogManager bkdlm, int logsegmentIdx, long transactionId) throws Exception { - List logSegments = bkdlm.getLogSegments(); - return ReadUtils.getLogRecordNotLessThanTxId( - bkdlm.getStreamName(), - logSegments.get(logsegmentIdx), - transactionId, - Executors.newSingleThreadExecutor(), - bkdlm.getReaderEntryStore(), - 10 - ); - } - - private CompletableFuture getFirstGreaterThanRecord(BKDistributedLogManager bkdlm, - int ledgerNo, DLSN dlsn) throws Exception { - List ledgerList = bkdlm.getLogSegments(); - return ReadUtils.asyncReadFirstUserRecord( - bkdlm.getStreamName(), ledgerList.get(ledgerNo), - 2, 16, new AtomicInteger(0), Executors.newFixedThreadPool(1), - bkdlm.getReaderEntryStore(), dlsn - ); - } - - private CompletableFuture getLastUserRecord(BKDistributedLogManager bkdlm, int ledgerNo) - throws Exception { - BKLogReadHandler readHandler = bkdlm.createReadHandler(); - List ledgerList = Utils.ioResult( - readHandler.readLogSegmentsFromStore( - LogSegmentMetadata.COMPARATOR, - LogSegmentFilter.DEFAULT_FILTER, - null) - ).getValue(); - return ReadUtils.asyncReadLastRecord( - bkdlm.getStreamName(), ledgerList.get(ledgerNo), - false, false, false, 2, 16, new AtomicInteger(0), Executors.newFixedThreadPool(1), - bkdlm.getReaderEntryStore() - ); - } - - @Test(timeout = 60000) - public void testForwardScanFirstRecord() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5, 1 /* txid */); - - DLSN dlsn = new DLSN(1, 0, 0); - CompletableFuture futureLogrec = getFirstGreaterThanRecord(bkdlm, 0, dlsn); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals("should be an exact match", dlsn, logrec.getDlsn()); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testForwardScanNotFirstRecord() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5, 1 /* txid */); - - DLSN dlsn = new DLSN(1, 1, 0); - CompletableFuture futureLogrec = getFirstGreaterThanRecord(bkdlm, 0, dlsn); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals("should be an exact match", dlsn, logrec.getDlsn()); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testForwardScanValidButNonExistentRecord() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5, 1 /* txid */); - - DLSN dlsn = new DLSN(1, 0, 1); - CompletableFuture futureLogrec = getFirstGreaterThanRecord(bkdlm, 0, dlsn); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals(new DLSN(1, 1, 0), logrec.getDlsn()); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testForwardScanForRecordAfterLedger() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5 /* user recs */ , 1 /* txid */); - - DLSN dlsn = new DLSN(2, 0, 0); - CompletableFuture futureLogrec = getFirstGreaterThanRecord(bkdlm, 0, dlsn); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals(null, logrec); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testForwardScanForRecordBeforeLedger() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - long txid = 1; - txid += DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5 /* user recs */ , txid); - txid += DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5 /* user recs */ , txid); - txid += DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0, 5 /* user recs */ , txid); - - DLSN dlsn = new DLSN(1, 3, 0); - CompletableFuture futureLogrec = getFirstGreaterThanRecord(bkdlm, 1, dlsn); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals(new DLSN(2, 0, 0), logrec.getDlsn()); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testForwardScanControlRecord() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 5 /* control recs */, 5, 1 /* txid */); - - DLSN dlsn = new DLSN(1, 3, 0); - CompletableFuture futureLogrec = getFirstGreaterThanRecord(bkdlm, 0, dlsn); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals(new DLSN(1, 5, 0), logrec.getDlsn()); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testGetLastRecordUserRecord() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 5 /* control recs */, 5, 1 /* txid */); - - CompletableFuture futureLogrec = getLastUserRecord(bkdlm, 0); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals(new DLSN(1, 9, 0), logrec.getDlsn()); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testGetLastRecordControlRecord() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - - AsyncLogWriter out = bkdlm.startAsyncLogSegmentNonPartitioned(); - int txid = 1; - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, false))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, true))); - Utils.ioResult(out.write(DLMTestUtil.getLargeLogRecordInstance(txid++, true))); - Utils.close(out); - - CompletableFuture futureLogrec = getLastUserRecord(bkdlm, 0); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals(new DLSN(1, 2, 0), logrec.getDlsn()); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testGetLastRecordAllControlRecords() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = (BKDistributedLogManager) createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 5 /* control recs */, 0, 1 /* txid */); - - CompletableFuture futureLogrec = getLastUserRecord(bkdlm, 0); - LogRecordWithDLSN logrec = Utils.ioResult(futureLogrec); - assertEquals(null, logrec); - bkdlm.close(); - } - - @Test(timeout = 60000) - public void testGetEntriesToSearch() throws Exception { - assertTrue(ReadUtils.getEntriesToSearch(2L, 1L, 10).isEmpty()); - assertEquals(Lists.newArrayList(1L), - ReadUtils.getEntriesToSearch(1L, 1L, 10)); - assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L), - ReadUtils.getEntriesToSearch(1L, 10L, 10)); - assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L), - ReadUtils.getEntriesToSearch(1L, 9L, 10)); - assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L), - ReadUtils.getEntriesToSearch(1L, 8L, 10)); - assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 11L), - ReadUtils.getEntriesToSearch(1L, 11L, 10)); - assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 12L), - ReadUtils.getEntriesToSearch(1L, 12L, 10)); - } - - @Test(timeout = 60000) - public void testGetEntriesToSearchByTxnId() throws Exception { - LogRecordWithDLSN firstRecord = - DLMTestUtil.getLogRecordWithDLSNInstance(new DLSN(1L, 0L, 0L), 999L); - LogRecordWithDLSN secondRecord = - DLMTestUtil.getLogRecordWithDLSNInstance(new DLSN(1L, 10L, 0L), 99L); - LogRecordWithDLSN thirdRecord = - DLMTestUtil.getLogRecordWithDLSNInstance(new DLSN(1L, 100L, 0L), 1099L); - // out-of-order sequence - assertTrue(ReadUtils.getEntriesToSearch(888L, firstRecord, secondRecord, 10).isEmpty()); - // same transaction id - assertTrue(ReadUtils.getEntriesToSearch(888L, firstRecord, firstRecord, 10).isEmpty()); - // small nways (nways = 2) - assertEquals(2, ReadUtils.getEntriesToSearch(888L, firstRecord, thirdRecord, 2).size()); - // small nways with equal transaction id - assertEquals(3, ReadUtils.getEntriesToSearch(1099L, firstRecord, thirdRecord, 2).size()); - LogRecordWithDLSN record1 = - DLMTestUtil.getLogRecordWithDLSNInstance(new DLSN(1L, 0L, 0L), 88L); - LogRecordWithDLSN record2 = - DLMTestUtil.getLogRecordWithDLSNInstance(new DLSN(1L, 12L, 0L), 888L); - LogRecordWithDLSN record3 = - DLMTestUtil.getLogRecordWithDLSNInstance(new DLSN(1L, 12L, 0L), 999L); - assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 10L, 11L), - ReadUtils.getEntriesToSearch(888L, record1, record2, 10)); - assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 11L), - ReadUtils.getEntriesToSearch(888L, record1, record3, 10)); - } - - @Test(timeout = 60000) - public void testGetLogRecordNotLessThanTxIdWithGreaterTxId() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0 /* control recs */, 1, 1 /* txid */); - - Optional result = - Utils.ioResult(getLogRecordNotLessThanTxId(bkdlm, 0, 999L)); - assertFalse(result.isPresent()); - } - - @Test(timeout = 60000) - public void testGetLogRecordNotLessThanTxIdWithLessTxId() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0 /* control recs */, 1, 999L /* txid */); - - Optional result = - Utils.ioResult(getLogRecordNotLessThanTxId(bkdlm, 0, 99L)); - assertTrue(result.isPresent()); - assertEquals(999L, result.get().getTransactionId()); - assertEquals(0L, result.get().getDlsn().getEntryId()); - assertEquals(0L, result.get().getDlsn().getSlotId()); - } - - @Test(timeout = 60000) - public void testGetLogRecordNotLessThanTxIdOnSmallSegment() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0 /* control recs */, 5, 1L /* txid */); - - Optional result = - Utils.ioResult(getLogRecordNotLessThanTxId(bkdlm, 0, 3L)); - assertTrue(result.isPresent()); - assertEquals(3L, result.get().getTransactionId()); - } - - @Test(timeout = 60000) - public void testGetLogRecordNotLessThanTxIdOnLargeSegment() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0 /* control recs */, 100, 1L /* txid */); - - Optional result = - Utils.ioResult(getLogRecordNotLessThanTxId(bkdlm, 0, 9L)); - assertTrue(result.isPresent()); - assertEquals(9L, result.get().getTransactionId()); - } - - @Test(timeout = 60000) - public void testGetLogRecordGreaterThanTxIdOnLargeSegment() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - DLMTestUtil.generateLogSegmentNonPartitioned(bkdlm, 0 /* control recs */, 100, 1L /* txid */, 3L); - - Optional result = - Utils.ioResult(getLogRecordNotLessThanTxId(bkdlm, 0, 23L)); - assertTrue(result.isPresent()); - assertEquals(25L, result.get().getTransactionId()); - } - - @Test(timeout = 60000) - public void testGetLogRecordGreaterThanTxIdOnSameTxId() throws Exception { - String streamName = runtime.getMethodName(); - BKDistributedLogManager bkdlm = createNewDLM(conf, streamName); - AsyncLogWriter out = bkdlm.startAsyncLogSegmentNonPartitioned(); - long txid = 1L; - for (int i = 0; i < 10; ++i) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid); - Utils.ioResult(out.write(record)); - txid += 1; - } - long txidToSearch = txid; - for (int i = 0; i < 10; ++i) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txidToSearch); - Utils.ioResult(out.write(record)); - } - for (int i = 0; i < 10; ++i) { - LogRecord record = DLMTestUtil.getLargeLogRecordInstance(txid); - Utils.ioResult(out.write(record)); - txid += 1; - } - Utils.close(out); - Optional result = - Utils.ioResult(getLogRecordNotLessThanTxId(bkdlm, 0, txidToSearch)); - assertTrue(result.isPresent()); - assertEquals(10L, result.get().getDlsn().getEntryId()); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReader.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReader.java deleted file mode 100644 index de880ee3d02..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestReader.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.common.concurrent.FutureEventListener; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.util.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * A Reader wraps reading next logic for testing. - */ -public class TestReader implements FutureEventListener { - - static final Logger LOG = LoggerFactory.getLogger(TestReader.class); - - final String readerName; - final DistributedLogManager dlm; - AsyncLogReader reader; - final DLSN startDLSN; - DLSN nextDLSN; - final boolean simulateErrors; - int delayMs; - final ScheduledExecutorService executorService; - - // Latches - - // Latch on notifying reader is ready to read - final CountDownLatch readyLatch; - // Latch no notifying reads are completed or errors are encountered - final CountDownLatch completionLatch; - // Latch no notifying reads are done. - final CountDownLatch countLatch; - - // States - final AtomicBoolean errorsFound; - final AtomicInteger readCount; - final AtomicInteger positionReaderCount; - - public TestReader(String name, - DistributedLogManager dlm, - DLSN startDLSN, - boolean simulateErrors, - int delayMs, - CountDownLatch readyLatch, - CountDownLatch countLatch, - CountDownLatch completionLatch) { - this.readerName = name; - this.dlm = dlm; - this.startDLSN = startDLSN; - this.simulateErrors = simulateErrors; - this.delayMs = delayMs; - this.readyLatch = readyLatch; - this.countLatch = countLatch; - this.completionLatch = completionLatch; - // States - this.errorsFound = new AtomicBoolean(false); - this.readCount = new AtomicInteger(0); - this.positionReaderCount = new AtomicInteger(0); - // Executors - this.executorService = Executors.newSingleThreadScheduledExecutor(); - } - - public AtomicInteger getNumReaderPositions() { - return this.positionReaderCount; - } - - public AtomicInteger getNumReads() { - return this.readCount; - } - - public boolean areErrorsFound() { - return errorsFound.get(); - } - - private int nextDelayMs() { - int newDelayMs = Math.min(delayMs * 2, 500); - if (0 == delayMs) { - newDelayMs = 10; - } - delayMs = newDelayMs; - return delayMs; - } - - private void positionReader(final DLSN dlsn) { - positionReaderCount.incrementAndGet(); - Runnable runnable = new Runnable() { - @Override - public void run() { - try { - AsyncLogReader reader = dlm.getAsyncLogReader(dlsn); - if (simulateErrors) { - ((BKAsyncLogReader) reader).simulateErrors(); - } - nextDLSN = dlsn; - LOG.info("Positioned reader {} at {}", readerName, dlsn); - if (null != TestReader.this.reader) { - Utils.close(TestReader.this.reader); - } - TestReader.this.reader = reader; - readNext(); - readyLatch.countDown(); - } catch (IOException exc) { - int nextMs = nextDelayMs(); - LOG.info("Encountered exception {} on opening reader {} at {}, retrying in {} ms", - exc, readerName, dlsn, nextMs); - positionReader(dlsn); - } - } - }; - executorService.schedule(runnable, delayMs, TimeUnit.MILLISECONDS); - } - - private void readNext() { - CompletableFuture record = reader.readNext(); - record.whenComplete(this); - } - - @Override - public void onSuccess(LogRecordWithDLSN value) { - try { - assertTrue(value.getDlsn().compareTo(nextDLSN) >= 0); - LOG.info("Received record {} from log {} for reader {}", - value.getDlsn(), dlm.getStreamName(), readerName); - assertFalse(value.isControl()); - assertEquals(0, value.getDlsn().getSlotId()); - DLMTestUtil.verifyLargeLogRecord(value); - } catch (Exception exc) { - LOG.error("Exception encountered when verifying received log record {} for reader {} :", - value.getDlsn(), readerName, exc); - errorsFound.set(true); - completionLatch.countDown(); - return; - } - readCount.incrementAndGet(); - countLatch.countDown(); - if (countLatch.getCount() <= 0) { - LOG.info("Reader {} is completed", readerName); - closeReader(); - completionLatch.countDown(); - } else { - LOG.info("Reader {} : read count becomes {}, latch = {}", - readerName, readCount.get(), countLatch.getCount()); - nextDLSN = value.getDlsn().getNextDLSN(); - readNext(); - } - } - - @Override - public void onFailure(Throwable cause) { - LOG.error("{} encountered exception on reading next record : ", readerName, cause); - closeReader(); - nextDelayMs(); - positionReader(nextDLSN); - } - - private void closeReader() { - if (null != reader) { - reader.asyncClose().whenComplete((value, cause) -> { - LOG.warn("Exception on closing reader {} : ", readerName, cause); - }); - } - } - - public void start() { - positionReader(startDLSN); - } - - public void stop() { - closeReader(); - executorService.shutdown(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java deleted file mode 100644 index 1a8dc7d8a48..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.concurrent.FutureEventListener; -import org.apache.bookkeeper.feature.SettableFeature; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.feature.CoreFeatureKeys; -import org.apache.distributedlog.impl.logsegment.BKLogSegmentEntryReader; -import org.apache.distributedlog.util.FailpointUtils; -import org.apache.distributedlog.util.Utils; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for RollLogSegments. - */ -public class TestRollLogSegments extends TestDistributedLogBase { - private static final Logger logger = LoggerFactory.getLogger(TestRollLogSegments.class); - - private static void ensureOnlyOneInprogressLogSegments(List segments) throws Exception { - int numInprogress = 0; - for (LogSegmentMetadata segment : segments) { - if (segment.isInProgress()) { - ++numInprogress; - } - } - assertEquals(1, numInprogress); - } - - @Test(timeout = 60000) - public void testDisableRollingLogSegments() throws Exception { - String name = "distrlog-disable-rolling-log-segments"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - confLocal.setLogSegmentRollingIntervalMinutes(0); - confLocal.setMaxLogSegmentBytes(40); - - int numEntries = 100; - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(confLocal, name); - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - - SettableFeature disableLogSegmentRolling = - (SettableFeature) dlm.getFeatureProvider() - .getFeature(CoreFeatureKeys.DISABLE_LOGSEGMENT_ROLLING.name().toLowerCase()); - disableLogSegmentRolling.set(true); - - final CountDownLatch latch = new CountDownLatch(numEntries); - - // send requests in parallel - for (int i = 1; i <= numEntries; i++) { - final int entryId = i; - writer.write(DLMTestUtil.getLogRecordInstance(entryId)).whenComplete(new FutureEventListener() { - - @Override - public void onSuccess(DLSN value) { - logger.info("Completed entry {} : {}.", entryId, value); - latch.countDown(); - } - - @Override - public void onFailure(Throwable cause) { - // nope - } - }); - } - latch.await(); - - // make sure all ensure blocks were executed - writer.closeAndComplete(); - - List segments = dlm.getLogSegments(); - assertEquals(1, segments.size()); - - dlm.close(); - } - - @Test(timeout = 600000) - public void testLastDLSNInRollingLogSegments() throws Exception { - final Map lastDLSNs = new HashMap(); - String name = "distrlog-lastdlsn-in-rolling-log-segments"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - confLocal.setLogSegmentRollingIntervalMinutes(0); - confLocal.setMaxLogSegmentBytes(40); - - int numEntries = 100; - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - - final CountDownLatch latch = new CountDownLatch(numEntries); - - // send requests in parallel to have outstanding requests - for (int i = 1; i <= numEntries; i++) { - final int entryId = i; - CompletableFuture writeFuture = - writer.write(DLMTestUtil.getLogRecordInstance(entryId)) - .whenComplete(new FutureEventListener() { - - @Override - public void onSuccess(DLSN value) { - logger.info("Completed entry {} : {}.", entryId, value); - synchronized (lastDLSNs) { - DLSN lastDLSN = lastDLSNs.get(value.getLogSegmentSequenceNo()); - if (null == lastDLSN || lastDLSN.compareTo(value) < 0) { - lastDLSNs.put(value.getLogSegmentSequenceNo(), value); - } - } - latch.countDown(); - } - - @Override - public void onFailure(Throwable cause) { - - } - }); - if (i == 1) { - // wait for first log segment created - Utils.ioResult(writeFuture); - } - } - latch.await(); - - // make sure all ensure blocks were executed. - writer.closeAndComplete(); - - List segments = dlm.getLogSegments(); - logger.info("lastDLSNs after writes {} {}", lastDLSNs.size(), lastDLSNs); - logger.info("segments after writes {} {}", segments.size(), segments); - assertTrue(segments.size() >= 2); - assertTrue(lastDLSNs.size() >= 2); - assertEquals(lastDLSNs.size(), segments.size()); - for (LogSegmentMetadata segment : segments) { - DLSN dlsnInMetadata = segment.getLastDLSN(); - DLSN dlsnSeen = lastDLSNs.get(segment.getLogSegmentSequenceNumber()); - assertNotNull(dlsnInMetadata); - assertNotNull(dlsnSeen); - if (dlsnInMetadata.compareTo(dlsnSeen) != 0) { - logger.error("Last dlsn recorded in log segment {} is different from the one already seen {}.", - dlsnInMetadata, dlsnSeen); - } - assertEquals(0, dlsnInMetadata.compareTo(dlsnSeen)); - } - - dlm.close(); - } - - @Test(timeout = 60000) - public void testUnableToRollLogSegments() throws Exception { - String name = "distrlog-unable-to-roll-log-segments"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - confLocal.setLogSegmentRollingIntervalMinutes(0); - confLocal.setMaxLogSegmentBytes(1); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - - long txId = 1L; - - // Create Log Segments - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId))); - - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_StartLogSegmentBeforeLedgerCreate, - FailpointUtils.FailPointActions.FailPointAction_Throw); - - try { - // If we couldn't open new log segment, we should keep using the old one - final int numRecords = 10; - final CountDownLatch latch = new CountDownLatch(numRecords); - for (int i = 0; i < numRecords; i++) { - writer.write(DLMTestUtil.getLogRecordInstance(++txId)).whenComplete(new FutureEventListener() { - @Override - public void onSuccess(DLSN value) { - logger.info("Completed entry : {}.", value); - latch.countDown(); - } - @Override - public void onFailure(Throwable cause) { - logger.error("Failed to write entries : ", cause); - } - }); - } - - latch.await(); - - writer.close(); - - List segments = dlm.getLogSegments(); - logger.info("LogSegments: {}", segments); - - assertEquals(1, segments.size()); - - long expectedTxID = 1L; - LogReader reader = dlm.getInputStream(DLSN.InitialDLSN); - LogRecordWithDLSN record = reader.readNext(false); - while (null != record) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(expectedTxID++, record.getTransactionId()); - assertEquals(record.getTransactionId() - 1, record.getSequenceId()); - - record = reader.readNext(false); - } - - assertEquals(12L, expectedTxID); - - reader.close(); - - dlm.close(); - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_StartLogSegmentBeforeLedgerCreate); - } - } - - @Test(timeout = 60000) - public void testRollingLogSegments() throws Exception { - logger.info("start testRollingLogSegments"); - String name = "distrlog-rolling-logsegments-hightraffic"; - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - confLocal.setLogSegmentRollingIntervalMinutes(0); - confLocal.setMaxLogSegmentBytes(1); - confLocal.setLogSegmentRollingConcurrency(Integer.MAX_VALUE); - - int numLogSegments = 10; - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKAsyncLogWriter writer = (BKAsyncLogWriter) dlm.startAsyncLogSegmentNonPartitioned(); - - final CountDownLatch latch = new CountDownLatch(numLogSegments); - long startTime = System.currentTimeMillis(); - // send requests in parallel to have outstanding requests - for (int i = 1; i <= numLogSegments; i++) { - final int entryId = i; - CompletableFuture writeFuture = writer.write(DLMTestUtil.getLogRecordInstance(entryId)) - .whenComplete(new FutureEventListener() { - @Override - public void onSuccess(DLSN value) { - logger.info("Completed entry {} : {}.", entryId, value); - latch.countDown(); - } - @Override - public void onFailure(Throwable cause) { - logger.error("Failed to write entries", cause); - } - }); - if (i == 1) { - // wait for first log segment created - Utils.ioResult(writeFuture); - } - } - latch.await(); - - logger.info("Took {} ms to completed all requests.", System.currentTimeMillis() - startTime); - - List segments = dlm.getLogSegments(); - logger.info("LogSegments : {}", segments); - logger.info("LogSegments size: {}", segments.size()); - - assertTrue(segments.size() >= 2); - ensureOnlyOneInprogressLogSegments(segments); - - int numSegmentsAfterAsyncWrites = segments.size(); - - // writer should work after rolling log segments - // there would be (numLogSegments/2) segments based on current rolling policy - for (int i = 1; i <= numLogSegments; i++) { - DLSN newDLSN = Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(numLogSegments + i))); - logger.info("Completed entry {} : {}", numLogSegments + i, newDLSN); - } - - segments = dlm.getLogSegments(); - logger.info("LogSegments : {}", segments); - logger.info("LogSegments size: {}", segments.size()); - - assertEquals(numSegmentsAfterAsyncWrites + numLogSegments / 2, segments.size()); - ensureOnlyOneInprogressLogSegments(segments); - - writer.close(); - dlm.close(); - } - - private void checkAndWaitWriterReaderPosition(BKLogSegmentWriter writer, long expectedWriterPosition, - BKAsyncLogReader reader, long expectedReaderPosition, - LedgerHandle inspector, long expectedLac) throws Exception { - while (getLedgerHandle(writer).getLastAddConfirmed() < expectedWriterPosition) { - Thread.sleep(1000); - } - assertEquals(expectedWriterPosition, getLedgerHandle(writer).getLastAddConfirmed()); - assertEquals(expectedLac, inspector.readLastConfirmed()); - EntryPosition readPosition = reader.getReadAheadReader().getNextEntryPosition(); - logger.info("ReadAhead moved read position {} : ", readPosition); - while (readPosition.getEntryId() < expectedReaderPosition) { - Thread.sleep(1000); - readPosition = reader.getReadAheadReader().getNextEntryPosition(); - logger.info("ReadAhead moved read position {} : ", readPosition); - } - assertEquals(expectedReaderPosition, readPosition.getEntryId()); - } - - @Test(timeout = 60000) - @SuppressWarnings("deprecation") - public void testCaughtUpReaderOnLogSegmentRolling() throws Exception { - String name = "distrlog-caughtup-reader-on-logsegment-rolling"; - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setOutputBufferSize(4 * 1024 * 1024); - confLocal.setTraceReadAheadMetadataChanges(true); - confLocal.setEnsembleSize(1); - confLocal.setWriteQuorumSize(1); - confLocal.setAckQuorumSize(1); - confLocal.setReadLACLongPollTimeout(99999999); - confLocal.setReaderIdleWarnThresholdMillis(2 * 99999999 + 1); - confLocal.setBKClientReadTimeout(99999999 + 1); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - BKSyncLogWriter writer = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - - // 1) writer added 5 entries. - final int numEntries = 5; - for (int i = 1; i <= numEntries; i++) { - writer.write(DLMTestUtil.getLogRecordInstance(i)); - writer.flush(); - writer.commit(); - } - - BKDistributedLogManager readDLM = (BKDistributedLogManager) createNewDLM(confLocal, name); - final BKAsyncLogReader reader = (BKAsyncLogReader) readDLM.getAsyncLogReader(DLSN.InitialDLSN); - - // 2) reader should be able to read 5 entries. - for (long i = 1; i <= numEntries; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - DLMTestUtil.verifyLogRecord(record); - assertEquals(i, record.getTransactionId()); - assertEquals(record.getTransactionId() - 1, record.getSequenceId()); - } - - BKLogSegmentWriter perStreamWriter = writer.segmentWriter; - BookKeeperClient bkc = DLMTestUtil.getBookKeeperClient(readDLM); - LedgerHandle readLh = bkc.get().openLedgerNoRecovery(getLedgerHandle(perStreamWriter).getId(), - BookKeeper.DigestType.CRC32, conf.getBKDigestPW().getBytes(UTF_8)); - - // Writer moved to lac = 9, while reader knows lac = 8 and moving to wait on 9 - checkAndWaitWriterReaderPosition(perStreamWriter, 9, reader, 9, readLh, 8); - - // write 6th record - writer.write(DLMTestUtil.getLogRecordInstance(numEntries + 1)); - writer.flush(); - // Writer moved to lac = 10, while reader knows lac = 9 and moving to wait on 10 - checkAndWaitWriterReaderPosition(perStreamWriter, 10, reader, 10, readLh, 9); - - // write records without commit to simulate similar failure cases - writer.write(DLMTestUtil.getLogRecordInstance(numEntries + 2)); - writer.flush(); - // Writer moved to lac = 11, while reader knows lac = 10 and moving to wait on 11 - checkAndWaitWriterReaderPosition(perStreamWriter, 11, reader, 11, readLh, 10); - - while (true) { - BKLogSegmentEntryReader entryReader = - (BKLogSegmentEntryReader) reader.getReadAheadReader().getCurrentSegmentReader().getEntryReader(); - if (null != entryReader && null != entryReader.getOutstandingLongPoll()) { - break; - } - Thread.sleep(1000); - } - logger.info("Waiting for long poll getting interrupted with metadata changed"); - - // simulate a recovery without closing ledger causing recording wrong last dlsn - BKLogWriteHandler writeHandler = writer.getCachedWriteHandler(); - writeHandler.completeAndCloseLogSegment( - writeHandler.inprogressZNodeName(perStreamWriter.getLogSegmentId(), - perStreamWriter.getStartTxId(), perStreamWriter.getLogSegmentSequenceNumber()), - perStreamWriter.getLogSegmentSequenceNumber(), - perStreamWriter.getLogSegmentId(), - perStreamWriter.getStartTxId(), perStreamWriter.getLastTxId(), - perStreamWriter.getPositionWithinLogSegment() - 1, - 9, - 0); - - BKSyncLogWriter anotherWriter = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned(); - anotherWriter.write(DLMTestUtil.getLogRecordInstance(numEntries + 3)); - anotherWriter.flush(); - anotherWriter.commit(); - anotherWriter.closeAndComplete(); - - for (long i = numEntries + 1; i <= numEntries + 3; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - DLMTestUtil.verifyLogRecord(record); - assertEquals(i, record.getTransactionId()); - } - - Utils.close(reader); - readDLM.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestSequenceID.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestSequenceID.java deleted file mode 100644 index 377629e0ebb..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestSequenceID.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; -import org.apache.bookkeeper.common.concurrent.FutureEventListener; -import org.apache.distributedlog.LogSegmentMetadata.LogSegmentMetadataVersion; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.util.Utils; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Test Cases related to sequence ids. - */ -public class TestSequenceID extends TestDistributedLogBase { - - private static final Logger logger = LoggerFactory.getLogger(TestSequenceID.class); - - @Test(timeout = 60000) - public void testCompleteV4LogSegmentAsV4() throws Exception { - completeSingleInprogressSegment(LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES.value, - LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES.value); - } - - @Test(timeout = 60000) - public void testCompleteV4LogSegmentAsV5() throws Exception { - completeSingleInprogressSegment(LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES.value, - LogSegmentMetadataVersion.VERSION_V5_SEQUENCE_ID.value); - } - - @Test(timeout = 60000) - public void testCompleteV5LogSegmentAsV4() throws Exception { - completeSingleInprogressSegment(LogSegmentMetadataVersion.VERSION_V5_SEQUENCE_ID.value, - LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES.value); - } - - @Test(timeout = 60000) - public void testCompleteV5LogSegmentAsV5() throws Exception { - completeSingleInprogressSegment(LogSegmentMetadataVersion.VERSION_V5_SEQUENCE_ID.value, - LogSegmentMetadataVersion.VERSION_V5_SEQUENCE_ID.value); - } - - private void completeSingleInprogressSegment(int writeVersion, int completeVersion) throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - confLocal.setDLLedgerMetadataLayoutVersion(writeVersion); - - String name = "distrlog-complete-single-inprogress-segment-versions-write-" - + writeVersion + "-complete-" + completeVersion; - - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(confLocal, name); - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(0L))); - - dlm.close(); - - DistributedLogConfiguration confLocal2 = new DistributedLogConfiguration(); - confLocal2.addConfiguration(confLocal); - confLocal2.setDLLedgerMetadataLayoutVersion(completeVersion); - - BKDistributedLogManager dlm2 = (BKDistributedLogManager) createNewDLM(confLocal2, name); - dlm2.startAsyncLogSegmentNonPartitioned(); - - List segments = dlm2.getLogSegments(); - assertEquals(1, segments.size()); - - if (LogSegmentMetadata.supportsSequenceId(writeVersion)) { - if (LogSegmentMetadata.supportsSequenceId(completeVersion)) { - // the inprogress log segment is written in v5 and complete log segment in v5, - // then it support monotonic sequence id - assertEquals(0L, segments.get(0).getStartSequenceId()); - } else { - // the inprogress log segment is written in v5 and complete log segment in v4, - // then it doesn't support monotonic sequence id - assertTrue(segments.get(0).getStartSequenceId() < 0); - } - } else { - // if the inprogress log segment is created prior to v5, it won't support monotonic sequence id - assertTrue(segments.get(0).getStartSequenceId() < 0); - } - - dlm2.close(); - } - - @Test(timeout = 60000) - public void testSequenceID() throws Exception { - DistributedLogConfiguration confLocalv4 = new DistributedLogConfiguration(); - confLocalv4.addConfiguration(conf); - confLocalv4.setImmediateFlushEnabled(true); - confLocalv4.setOutputBufferSize(0); - confLocalv4.setDLLedgerMetadataLayoutVersion(LogSegmentMetadataVersion.VERSION_V4_ENVELOPED_ENTRIES.value); - - String name = "distrlog-sequence-id"; - - BKDistributedLogManager readDLM = (BKDistributedLogManager) createNewDLM(conf, name); - AsyncLogReader reader = null; - final LinkedBlockingQueue readRecords = - new LinkedBlockingQueue(); - - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(confLocalv4, name); - - long txId = 0L; - - for (int i = 0; i < 3; i++) { - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - for (int j = 0; j < 2; j++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - - if (null == reader) { - reader = readDLM.getAsyncLogReader(DLSN.InitialDLSN); - final AsyncLogReader r = reader; - reader.readNext().whenComplete(new FutureEventListener() { - @Override - public void onSuccess(LogRecordWithDLSN record) { - readRecords.add(record); - r.readNext().whenComplete(this); - } - - @Override - public void onFailure(Throwable cause) { - logger.error("Encountered exception on reading next : ", cause); - } - }); - } - } - writer.closeAndComplete(); - } - - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId++))); - - List segments = dlm.getLogSegments(); - assertEquals(4, segments.size()); - for (int i = 0; i < 3; i++) { - assertFalse(segments.get(i).isInProgress()); - assertTrue(segments.get(i).getStartSequenceId() < 0); - } - assertTrue(segments.get(3).isInProgress()); - assertTrue(segments.get(3).getStartSequenceId() < 0); - - dlm.close(); - - // simulate upgrading from v4 -> v5 - - DistributedLogConfiguration confLocalv5 = new DistributedLogConfiguration(); - confLocalv5.addConfiguration(conf); - confLocalv5.setImmediateFlushEnabled(true); - confLocalv5.setOutputBufferSize(0); - confLocalv5.setDLLedgerMetadataLayoutVersion(LogSegmentMetadataVersion.VERSION_V5_SEQUENCE_ID.value); - - BKDistributedLogManager dlmv5 = (BKDistributedLogManager) createNewDLM(confLocalv5, name); - for (int i = 0; i < 3; i++) { - BKAsyncLogWriter writerv5 = dlmv5.startAsyncLogSegmentNonPartitioned(); - for (int j = 0; j < 2; j++) { - Utils.ioResult(writerv5.write(DLMTestUtil.getLogRecordInstance(txId++))); - } - writerv5.closeAndComplete(); - } - BKAsyncLogWriter writerv5 = dlmv5.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(writerv5.write(DLMTestUtil.getLogRecordInstance(txId++))); - - List segmentsv5 = dlmv5.getLogSegments(); - assertEquals(8, segmentsv5.size()); - - assertFalse(segmentsv5.get(3).isInProgress()); - assertTrue(segmentsv5.get(3).getStartSequenceId() < 0); - - long startSequenceId = 0L; - for (int i = 4; i < 7; i++) { - assertFalse(segmentsv5.get(i).isInProgress()); - assertEquals(startSequenceId, segmentsv5.get(i).getStartSequenceId()); - startSequenceId += 2L; - } - - assertTrue(segmentsv5.get(7).isInProgress()); - assertEquals(startSequenceId, segmentsv5.get(7).getStartSequenceId()); - - dlmv5.close(); - - // rollback from v5 to v4 - - BKDistributedLogManager dlmv4 = (BKDistributedLogManager) createNewDLM(confLocalv4, name); - for (int i = 0; i < 3; i++) { - BKAsyncLogWriter writerv4 = dlmv4.startAsyncLogSegmentNonPartitioned(); - for (int j = 0; j < 2; j++) { - Utils.ioResult(writerv4.write(DLMTestUtil.getLogRecordInstance(txId++))); - } - writerv4.closeAndComplete(); - } - - List segmentsv4 = dlmv4.getLogSegments(); - assertEquals(11, segmentsv4.size()); - - for (int i = 7; i < 11; i++) { - assertFalse(segmentsv4.get(i).isInProgress()); - assertTrue(segmentsv4.get(i).getStartSequenceId() < 0); - } - - dlmv4.close(); - - // wait until readers read all records - while (readRecords.size() < txId) { - Thread.sleep(100); - } - - assertEquals(txId, readRecords.size()); - long sequenceId = Long.MIN_VALUE; - for (LogRecordWithDLSN record : readRecords) { - if (record.getDlsn().getLogSegmentSequenceNo() <= 4) { - assertTrue(record.getSequenceId() < 0); - assertTrue(record.getSequenceId() > sequenceId); - sequenceId = record.getSequenceId(); - } else if (record.getDlsn().getLogSegmentSequenceNo() <= 7) { - if (sequenceId < 0L) { - sequenceId = 0L; - } - assertEquals(sequenceId, record.getSequenceId()); - ++sequenceId; - } else if (record.getDlsn().getLogSegmentSequenceNo() >= 9) { - if (sequenceId > 0) { - sequenceId = Long.MIN_VALUE; - } - assertTrue(record.getSequenceId() < 0); - assertTrue(record.getSequenceId() > sequenceId); - sequenceId = record.getSequenceId(); - } - } - - readDLM.close(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTruncate.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTruncate.java deleted file mode 100644 index e32b5f2f7a5..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTruncate.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.distributedlog.LogSegmentMetadata.TruncationStatus; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.util.Utils; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for truncation. - */ -public class TestTruncate extends TestDistributedLogBase { - static final Logger LOG = LoggerFactory.getLogger(TestTruncate.class); - - protected static DistributedLogConfiguration conf = - new DistributedLogConfiguration() - .setLockTimeout(10) - .setOutputBufferSize(0) - .setPeriodicFlushFrequencyMilliSeconds(10) - .setSchedulerShutdownTimeoutMs(0) - .setDLLedgerMetadataLayoutVersion( - LogSegmentMetadata.LogSegmentMetadataVersion.VERSION_V2_LEDGER_SEQNO.value); - - static void updateCompletionTime(ZooKeeperClient zkc, - LogSegmentMetadata l, long completionTime) throws Exception { - LogSegmentMetadata newSegment = l.mutator().setCompletionTime(completionTime).build(); - DLMTestUtil.updateSegmentMetadata(zkc, newSegment); - } - - static void setTruncationStatus(ZooKeeperClient zkc, - LogSegmentMetadata l, - TruncationStatus status) throws Exception { - LogSegmentMetadata newSegment = - l.mutator().setTruncationStatus(status).build(); - DLMTestUtil.updateSegmentMetadata(zkc, newSegment); - } - - @Test(timeout = 60000) - public void testPurgeLogs() throws Exception { - String name = "distrlog-purge-logs"; - URI uri = createDLMURI("/" + name); - - populateData(new HashMap(), conf, name, 10, 10, false); - - DistributedLogManager distributedLogManager = createNewDLM(conf, name); - - List segments = distributedLogManager.getLogSegments(); - LOG.info("Segments before modifying completion time : {}", segments); - - ZooKeeperClient zkc = TestZooKeeperClientBuilder.newBuilder(conf) - .uri(uri) - .build(); - - // Update completion time of first 5 segments - long newTimeMs = System.currentTimeMillis() - 60 * 60 * 1000 * 2; - for (int i = 0; i < 5; i++) { - LogSegmentMetadata segment = segments.get(i); - updateCompletionTime(zkc, segment, newTimeMs + i); - } - zkc.close(); - - segments = distributedLogManager.getLogSegments(); - LOG.info("Segments after modifying completion time : {}", segments); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setRetentionPeriodHours(1); - confLocal.setExplicitTruncationByApplication(false); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - long txid = 1 + 10 * 10; - for (int j = 1; j <= 10; j++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid++))); - } - - // wait until truncation task to be completed. - BKAsyncLogWriter bkLogWriter = (BKAsyncLogWriter) writer; - CompletableFuture> truncationAttempt = bkLogWriter.getLastTruncationAttempt(); - while (truncationAttempt == null || !truncationAttempt.isDone()) { - TimeUnit.MILLISECONDS.sleep(20); - truncationAttempt = bkLogWriter.getLastTruncationAttempt(); - } - - assertEquals(6, distributedLogManager.getLogSegments().size()); - - Utils.close(writer); - dlm.close(); - - distributedLogManager.close(); - } - - @Test(timeout = 60000) - public void testTruncation() throws Exception { - String name = "distrlog-truncation"; - - long txid = 1; - Map txid2DLSN = new HashMap(); - Pair pair = - populateData(txid2DLSN, conf, name, 4, 10, true); - - Thread.sleep(1000); - - // delete invalid dlsn - assertFalse(Utils.ioResult(pair.getRight().truncate(DLSN.InvalidDLSN))); - verifyEntries(name, 1, 1, 5 * 10); - - for (int i = 1; i <= 4; i++) { - int txn = (i - 1) * 10 + i; - DLSN dlsn = txid2DLSN.get((long) txn); - assertTrue(Utils.ioResult(pair.getRight().truncate(dlsn))); - verifyEntries(name, 1, (i - 1) * 10 + 1, (5 - i + 1) * 10); - } - - // Delete higher dlsn - int txn = 43; - DLSN dlsn = txid2DLSN.get((long) txn); - assertTrue(Utils.ioResult(pair.getRight().truncate(dlsn))); - verifyEntries(name, 1, 41, 10); - - Utils.close(pair.getRight()); - pair.getLeft().close(); - } - - @Test(timeout = 60000) - public void testExplicitTruncation() throws Exception { - String name = "distrlog-truncation-explicit"; - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setExplicitTruncationByApplication(true); - - Map txid2DLSN = new HashMap(); - Pair pair = - populateData(txid2DLSN, confLocal, name, 4, 10, true); - - Thread.sleep(1000); - - for (int i = 1; i <= 4; i++) { - int txn = (i - 1) * 10 + i; - DLSN dlsn = txid2DLSN.get((long) txn); - assertTrue(Utils.ioResult(pair.getRight().truncate(dlsn))); - verifyEntries(name, 1, (i - 1) * 10 + 1, (5 - i + 1) * 10); - } - - // Delete higher dlsn - int txn = 43; - DLSN dlsn = txid2DLSN.get((long) txn); - assertTrue(Utils.ioResult(pair.getRight().truncate(dlsn))); - verifyEntries(name, 1, 41, 10); - - Utils.close(pair.getRight()); - pair.getLeft().close(); - - // Try force truncation - BKDistributedLogManager dlm = (BKDistributedLogManager) createNewDLM(confLocal, name); - BKLogWriteHandler handler = dlm.createWriteHandler(true); - Utils.ioResult(handler.purgeLogSegmentsOlderThanTxnId(Integer.MAX_VALUE)); - - verifyEntries(name, 1, 41, 10); - } - - @Test(timeout = 60000) - public void testOnlyPurgeSegmentsBeforeNoneFullyTruncatedSegment() throws Exception { - String name = "distrlog-only-purge-segments-before-none-fully-truncated-segment"; - URI uri = createDLMURI("/" + name); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setExplicitTruncationByApplication(true); - - // populate data - populateData(new HashMap(), confLocal, name, 4, 10, false); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - List segments = dlm.getLogSegments(); - LOG.info("Segments before modifying segment status : {}", segments); - - ZooKeeperClient zkc = TestZooKeeperClientBuilder.newBuilder(conf) - .uri(uri) - .build(); - setTruncationStatus(zkc, segments.get(0), TruncationStatus.PARTIALLY_TRUNCATED); - for (int i = 1; i < 4; i++) { - LogSegmentMetadata segment = segments.get(i); - setTruncationStatus(zkc, segment, TruncationStatus.TRUNCATED); - } - List segmentsAfterTruncated = dlm.getLogSegments(); - - dlm.purgeLogsOlderThan(999999); - List newSegments = dlm.getLogSegments(); - LOG.info("Segments after purge segments older than 999999 : {}", newSegments); - assertArrayEquals(segmentsAfterTruncated.toArray(new LogSegmentMetadata[segmentsAfterTruncated.size()]), - newSegments.toArray(new LogSegmentMetadata[newSegments.size()])); - - dlm.close(); - - // Update completion time of all 4 segments - long newTimeMs = System.currentTimeMillis() - 60 * 60 * 1000 * 10; - for (int i = 0; i < 4; i++) { - LogSegmentMetadata segment = newSegments.get(i); - updateCompletionTime(zkc, segment, newTimeMs + i); - } - - DistributedLogConfiguration newConf = new DistributedLogConfiguration(); - newConf.addConfiguration(confLocal); - newConf.setRetentionPeriodHours(1); - - DistributedLogManager newDLM = createNewDLM(newConf, name); - AsyncLogWriter newWriter = newDLM.startAsyncLogSegmentNonPartitioned(); - long txid = 1 + 4 * 10; - for (int j = 1; j <= 10; j++) { - Utils.ioResult(newWriter.write(DLMTestUtil.getLogRecordInstance(txid++))); - } - - // to make sure the truncation task is executed - DLSN lastDLSN = Utils.ioResult(newDLM.getLastDLSNAsync()); - LOG.info("Get last dlsn of stream {} : {}", name, lastDLSN); - - assertEquals(5, newDLM.getLogSegments().size()); - - Utils.close(newWriter); - newDLM.close(); - - zkc.close(); - } - - @Test(timeout = 60000) - public void testPartiallyTruncateTruncatedSegments() throws Exception { - String name = "distrlog-partially-truncate-truncated-segments"; - URI uri = createDLMURI("/" + name); - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setExplicitTruncationByApplication(true); - - // populate - Map dlsnMap = new HashMap(); - populateData(dlsnMap, confLocal, name, 4, 10, false); - - DistributedLogManager dlm = createNewDLM(confLocal, name); - List segments = dlm.getLogSegments(); - LOG.info("Segments before modifying segment status : {}", segments); - - ZooKeeperClient zkc = TestZooKeeperClientBuilder.newBuilder(conf) - .uri(uri) - .build(); - for (int i = 0; i < 4; i++) { - LogSegmentMetadata segment = segments.get(i); - setTruncationStatus(zkc, segment, TruncationStatus.TRUNCATED); - } - - List newSegments = dlm.getLogSegments(); - LOG.info("Segments after changing truncation status : {}", newSegments); - - dlm.close(); - - DistributedLogManager newDLM = createNewDLM(confLocal, name); - AsyncLogWriter newWriter = newDLM.startAsyncLogSegmentNonPartitioned(); - Utils.ioResult(newWriter.truncate(dlsnMap.get(15L))); - - List newSegments2 = newDLM.getLogSegments(); - assertArrayEquals(newSegments.toArray(new LogSegmentMetadata[4]), - newSegments2.toArray(new LogSegmentMetadata[4])); - - Utils.close(newWriter); - newDLM.close(); - zkc.close(); - } - - private Pair populateData( - Map txid2DLSN, DistributedLogConfiguration confLocal, - String name, int numLogSegments, int numEntriesPerLogSegment, - boolean createInprogressLogSegment) throws Exception { - long txid = 1; - for (long i = 1; i <= numLogSegments; i++) { - LOG.info("Writing Log Segment {}.", i); - DistributedLogManager dlm = createNewDLM(confLocal, name); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - for (int j = 1; j <= numEntriesPerLogSegment; j++) { - long curTxId = txid++; - DLSN dlsn = Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(curTxId))); - txid2DLSN.put(curTxId, dlsn); - } - Utils.close(writer); - dlm.close(); - } - - if (createInprogressLogSegment) { - DistributedLogManager dlm = createNewDLM(confLocal, name); - AsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned(); - for (int j = 1; j <= 10; j++) { - long curTxId = txid++; - DLSN dlsn = Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(curTxId))); - txid2DLSN.put(curTxId, dlsn); - } - return new ImmutablePair(dlm, writer); - } else { - return null; - } - } - - private void verifyEntries(String name, long readFromTxId, long startTxId, int numEntries) throws Exception { - DistributedLogManager dlm = createNewDLM(conf, name); - LogReader reader = dlm.getInputStream(readFromTxId); - - long txid = startTxId; - int numRead = 0; - LogRecord r = reader.readNext(false); - while (null != r) { - DLMTestUtil.verifyLogRecord(r); - assertEquals(txid++, r.getTransactionId()); - ++numRead; - r = reader.readNext(false); - } - assertEquals(numEntries, numRead); - reader.close(); - dlm.close(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTxnId.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTxnId.java deleted file mode 100644 index 2eb6a61683b..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestTxnId.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for RollLogSegments. - */ -public class TestTxnId extends TestDistributedLogBase { - private static final Logger logger = LoggerFactory.getLogger(TestRollLogSegments.class); - - @Test - public void testRecoveryAfterBookieCrash() throws Exception { - String name = "txnid-after-crash"; - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setEnsembleSize(5) - .setWriteQuorumSize(5) - .setAckQuorumSize(5) - .setLogSegmentRollingIntervalMinutes(0) - .setLogSegmentRollingConcurrency(-1) - .setMaxLogSegmentBytes(400000); - - bkutil.addBookie(); - bkutil.addBookie(); - - try (BKDistributedLogManager dlm = createNewDLM(conf, name); - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned()) { - writer.write(DLMTestUtil.getLogRecordInstance(1, 100000)).join(); - writer.write(DLMTestUtil.getLogRecordInstance(2, 100000)).join(); - - bkutil.removeBookie(); - bkutil.removeBookie(); - - try { - writer.write(DLMTestUtil.getLogRecordInstance(3, 100000)).join(); - Assert.fail("Shouldn't have succeeded"); - } catch (Exception e) { - // expected - } - - writer.write(DLMTestUtil.getLogRecordInstance(4, 100000)).join(); - Assert.fail("Shouldn't be able to write"); - } catch (Exception e) { - // expected - } - - bkutil.addBookie(); - bkutil.addBookie(); - - try (BKDistributedLogManager dlm = createNewDLM(conf, name); - BKAsyncLogWriter writer = dlm.startAsyncLogSegmentNonPartitioned()) { - long firstTxid = dlm.getLastTxId() + 1; - for (int i = 0; i < 20; i++) { - logger.info("Writing entry {}", i); - writer.write(DLMTestUtil.getLogRecordInstance(firstTxid + i, 100000)).join(); - Thread.sleep(100); - } - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestWriteLimiter.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestWriteLimiter.java deleted file mode 100644 index 898bc86fe22..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestWriteLimiter.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import org.apache.bookkeeper.feature.Feature; -import org.apache.bookkeeper.feature.SettableFeature; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.distributedlog.exceptions.OverCapacityException; -import org.apache.distributedlog.util.SimplePermitLimiter; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test Cases for {@link org.apache.distributedlog.util.SimplePermitLimiter}. - */ -public class TestWriteLimiter { - static final Logger LOG = LoggerFactory.getLogger(TestWriteLimiter.class); - - SimplePermitLimiter createPermitLimiter(boolean darkmode, int permits) { - return createPermitLimiter(darkmode, permits, new SettableFeature("", 0)); - } - - SimplePermitLimiter createPermitLimiter(boolean darkmode, int permits, Feature feature) { - return new SimplePermitLimiter(darkmode, permits, new NullStatsLogger(), false, feature); - } - - @Test(timeout = 60000) - public void testGlobalOnly() throws Exception { - SimplePermitLimiter streamLimiter = createPermitLimiter(false, Integer.MAX_VALUE); - SimplePermitLimiter globalLimiter = createPermitLimiter(false, 1); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - try { - limiter.acquire(); - fail("should have thrown global limit exception"); - } catch (OverCapacityException ex) { - } - assertPermits(streamLimiter, 1, globalLimiter, 1); - limiter.release(); - assertPermits(streamLimiter, 0, globalLimiter, 0); - } - - @Test(timeout = 60000) - public void testStreamOnly() throws Exception { - SimplePermitLimiter streamLimiter = createPermitLimiter(false, 1); - SimplePermitLimiter globalLimiter = createPermitLimiter(false, Integer.MAX_VALUE); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - try { - limiter.acquire(); - fail("should have thrown stream limit exception"); - } catch (OverCapacityException ex) { - } - assertPermits(streamLimiter, 1, globalLimiter, 1); - } - - @Test(timeout = 60000) - public void testDarkmode() throws Exception { - SimplePermitLimiter streamLimiter = createPermitLimiter(true, Integer.MAX_VALUE); - SimplePermitLimiter globalLimiter = createPermitLimiter(true, 1); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - limiter.acquire(); - assertPermits(streamLimiter, 2, globalLimiter, 2); - } - - @Test(timeout = 60000) - public void testDarkmodeWithDisabledFeature() throws Exception { - SettableFeature feature = new SettableFeature("test", 10000); - SimplePermitLimiter streamLimiter = createPermitLimiter(true, 1, feature); - SimplePermitLimiter globalLimiter = createPermitLimiter(true, Integer.MAX_VALUE, feature); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - limiter.acquire(); - assertPermits(streamLimiter, 2, globalLimiter, 2); - limiter.release(); - limiter.release(); - assertPermits(streamLimiter, 0, globalLimiter, 0); - } - - @Test(timeout = 60000) - public void testDisabledFeature() throws Exception { - // Disable darkmode, but should still ignore limits because of the feature. - SettableFeature feature = new SettableFeature("test", 10000); - SimplePermitLimiter streamLimiter = createPermitLimiter(false, 1, feature); - SimplePermitLimiter globalLimiter = createPermitLimiter(false, Integer.MAX_VALUE, feature); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - limiter.acquire(); - assertPermits(streamLimiter, 2, globalLimiter, 2); - limiter.release(); - limiter.release(); - assertPermits(streamLimiter, 0, globalLimiter, 0); - } - - @Test(timeout = 60000) - public void testSetDisableFeatureAfterAcquireAndBeforeRelease() throws Exception { - SettableFeature feature = new SettableFeature("test", 0); - SimplePermitLimiter streamLimiter = createPermitLimiter(false, 2, feature); - SimplePermitLimiter globalLimiter = createPermitLimiter(false, Integer.MAX_VALUE, feature); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - limiter.acquire(); - assertPermits(streamLimiter, 2, globalLimiter, 2); - feature.set(10000); - limiter.release(); - limiter.release(); - assertPermits(streamLimiter, 0, globalLimiter, 0); - } - - @Test(timeout = 60000) - public void testUnsetDisableFeatureAfterPermitsExceeded() throws Exception { - SettableFeature feature = new SettableFeature("test", 10000); - SimplePermitLimiter streamLimiter = createPermitLimiter(false, 1, feature); - SimplePermitLimiter globalLimiter = createPermitLimiter(false, Integer.MAX_VALUE, feature); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - limiter.acquire(); - limiter.acquire(); - limiter.acquire(); - assertPermits(streamLimiter, 4, globalLimiter, 4); - feature.set(0); - limiter.release(); - assertPermits(streamLimiter, 3, globalLimiter, 3); - try { - limiter.acquire(); - fail("should have thrown stream limit exception"); - } catch (OverCapacityException ex) { - } - assertPermits(streamLimiter, 3, globalLimiter, 3); - limiter.release(); - limiter.release(); - limiter.release(); - assertPermits(streamLimiter, 0, globalLimiter, 0); - } - - @Test(timeout = 60000) - public void testUnsetDisableFeatureBeforePermitsExceeded() throws Exception { - SettableFeature feature = new SettableFeature("test", 0); - SimplePermitLimiter streamLimiter = createPermitLimiter(false, 1, feature); - SimplePermitLimiter globalLimiter = createPermitLimiter(false, Integer.MAX_VALUE, feature); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - try { - limiter.acquire(); - fail("should have thrown stream limit exception"); - } catch (OverCapacityException ex) { - } - assertPermits(streamLimiter, 1, globalLimiter, 1); - feature.set(10000); - limiter.acquire(); - assertPermits(streamLimiter, 2, globalLimiter, 2); - } - - @Test(timeout = 60000) - public void testDarkmodeGlobalUnderStreamOver() throws Exception { - SimplePermitLimiter streamLimiter = createPermitLimiter(true, 1); - SimplePermitLimiter globalLimiter = createPermitLimiter(true, 2); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - limiter.acquire(); - assertPermits(streamLimiter, 2, globalLimiter, 2); - limiter.release(); - limiter.release(); - assertPermits(streamLimiter, 0, globalLimiter, 0); - } - - @Test(timeout = 60000) - public void testDarkmodeGlobalOverStreamUnder() throws Exception { - SimplePermitLimiter streamLimiter = createPermitLimiter(true, 2); - SimplePermitLimiter globalLimiter = createPermitLimiter(true, 1); - WriteLimiter limiter = new WriteLimiter("test", streamLimiter, globalLimiter); - limiter.acquire(); - limiter.acquire(); - assertPermits(streamLimiter, 2, globalLimiter, 2); - limiter.release(); - assertPermits(streamLimiter, 1, globalLimiter, 1); - limiter.release(); - assertPermits(streamLimiter, 0, globalLimiter, 0); - } - - void assertPermits(SimplePermitLimiter streamLimiter, - int streamPermits, SimplePermitLimiter globalLimiter, int globalPermits) { - assertEquals(streamPermits, streamLimiter.getPermits()); - assertEquals(globalPermits, globalLimiter.getPermits()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java deleted file mode 100644 index a9ff1d1cbea..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.zookeeper.BoundExponentialBackoffRetryPolicy; -import org.apache.distributedlog.ZooKeeperClient.Credentials; -import org.apache.distributedlog.ZooKeeperClient.DigestCredentials; -import org.apache.distributedlog.zk.ZKTransaction; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test Cases for {@link org.apache.distributedlog.ZooKeeperClient}. - */ -public class TestZooKeeperClient extends ZooKeeperClusterTestCase { - static final Logger LOG = LoggerFactory.getLogger(TestZooKeeperClient.class); - - private static final int sessionTimeoutMs = 2000; - - private ZooKeeperClient zkc; - - @Before - public void setup() throws Exception { - zkc = buildClient(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - } - - private ZooKeeperClientBuilder clientBuilder() throws Exception { - return clientBuilder(sessionTimeoutMs); - } - - private ZooKeeperClientBuilder clientBuilder(int sessionTimeoutMs) - throws Exception { - return ZooKeeperClientBuilder.newBuilder() - .name("zkc") - .uri(DLMTestUtil.createDLMURI(zkPort, "/")) - .sessionTimeoutMs(sessionTimeoutMs) - .zkServers(zkServers) - .retryPolicy(new BoundExponentialBackoffRetryPolicy(100, 200, 2)); - } - - private ZooKeeperClient buildClient() throws Exception { - return clientBuilder().zkAclId(null).build(); - } - - private ZooKeeperClient buildAuthdClient(String id) throws Exception { - return clientBuilder().zkAclId(id).build(); - } - - private void rmAll(ZooKeeperClient client, String path) throws Exception { - List nodes = client.get().getChildren(path, false); - for (String node : nodes) { - String childPath = path + "/" + node; - rmAll(client, childPath); - } - client.get().delete(path, 0); - } - - @Test(timeout = 60000) - public void testAclCreatePerms() throws Exception { - ZooKeeperClient zkcAuth = buildAuthdClient("test"); - zkcAuth.get().create("/test", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - zkcAuth.get().create("/test/key1", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - zkcAuth.get().create("/test/key2", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - - ZooKeeperClient zkcNoAuth = buildClient(); - zkcNoAuth.get().create("/test/key1/key1", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - try { - zkcNoAuth.get().create("/test/key2/key1", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - fail("create should fail on acl protected key"); - } catch (KeeperException.NoAuthException ex) { - LOG.info("caught exception writing to protected key", ex); - } - - rmAll(zkcAuth, "/test"); - } - - @Test(timeout = 60000) - public void testAclNullIdDisablesAuth() throws Exception { - ZooKeeperClient zkcAuth = buildAuthdClient(null); - zkcAuth.get().create("/test", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - zkcAuth.get().create("/test/key1", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - try { - zkcAuth.get().create("/test/key2", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - fail("create should fail because we're not authenticated"); - } catch (KeeperException.InvalidACLException ex) { - LOG.info("caught exception writing to protected key", ex); - } - - rmAll(zkcAuth, "/test"); - } - - @Test(timeout = 60000) - public void testAclAllowsReadsForNoAuth() throws Exception { - ZooKeeperClient zkcAuth = buildAuthdClient("test"); - zkcAuth.get().create("/test", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - zkcAuth.get().create("/test/key1", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - zkcAuth.get().create("/test/key1/key2", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - - ZooKeeperClient zkcNoAuth = buildClient(); - List nodes = null; - String path = "/test"; - nodes = zkcNoAuth.get().getChildren(path, false); - path = path + "/" + nodes.get(0); - nodes = zkcNoAuth.get().getChildren(path, false); - assertEquals("key2", nodes.get(0)); - - ZooKeeperClient zkcAuth2 = buildAuthdClient("test2"); - path = "/test"; - nodes = zkcNoAuth.get().getChildren(path, false); - path = path + "/" + nodes.get(0); - nodes = zkcNoAuth.get().getChildren(path, false); - assertEquals("key2", nodes.get(0)); - - rmAll(zkcAuth, "/test"); - } - - @Test(timeout = 60000) - public void testAclDigestCredentialsBasics() throws Exception { - ZooKeeperClient zkcAuth = buildClient(); - zkcAuth.get().create("/test", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - try { - zkcAuth.get().create("/test/key1", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - fail("should have failed"); - } catch (Exception ex) { - } - - Credentials credentials = new DigestCredentials("test", "test"); - credentials.authenticate(zkcAuth.get()); - - // Should not throw now that we're authenticated. - zkcAuth.get().create("/test/key1", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - - rmAll(zkcAuth, "/test"); - } - - @Test(timeout = 60000) - public void testAclNoopCredentialsDoesNothing() throws Exception { - Credentials.NONE.authenticate(null); - } - - class FailingCredentials implements Credentials { - boolean shouldFail = true; - @Override - public void authenticate(ZooKeeper zooKeeper) { - if (shouldFail) { - throw new RuntimeException("authfailed"); - } - } - public void setShouldFail(boolean shouldFail) { - this.shouldFail = shouldFail; - } - } - - @Test(timeout = 60000) - public void testAclFailedAuthenticationCanBeRecovered() throws Exception { - FailingCredentials credentials = new FailingCredentials(); - ZooKeeperClient zkc = new ZooKeeperClient("test", 2000, 2000, zkServers, - null, NullStatsLogger.INSTANCE, 1, 10000, credentials); - - try { - zkc.get(); - fail("should have failed on auth"); - } catch (Exception ex) { - assertEquals("authfailed", ex.getMessage()); - } - - // Should recover fine - credentials.setShouldFail(false); - zkc.get().create("/test", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - - rmAll(zkc, "/test"); - } - - private void expireZooKeeperSession(ZooKeeper zk, int timeout) - throws IOException, InterruptedException, KeeperException { - final CountDownLatch latch = new CountDownLatch(1); - - ZooKeeper newZk = new ZooKeeper(zkServers, timeout, new Watcher() { - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.None && event.getState() == KeeperState.SyncConnected) { - latch.countDown(); - } - }}, - zk.getSessionId(), - zk.getSessionPasswd()); - - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - throw KeeperException.create(KeeperException.Code.CONNECTIONLOSS); - } - - newZk.close(); - } - - private CountDownLatch awaitConnectionEvent(final KeeperState state, final ZooKeeperClient zkc) { - final CountDownLatch connected = new CountDownLatch(1); - Watcher watcher = new Watcher() { - @Override - public void process(WatchedEvent event) { - if (event.getType() == EventType.None && event.getState() == state) { - connected.countDown(); - } - } - }; - zkc.register(watcher); - return connected; - } - - /** - * {@link https://issues.apache.org/jira/browse/DL-34}. - */ - @Ignore - @Test(timeout = 60000) - public void testAclAuthSpansExpiration() throws Exception { - ZooKeeperClient zkcAuth = buildAuthdClient("test"); - zkcAuth.get().create("/test", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - - CountDownLatch expired = awaitConnectionEvent(KeeperState.Expired, zkcAuth); - CountDownLatch connected = awaitConnectionEvent(KeeperState.SyncConnected, zkcAuth); - - expireZooKeeperSession(zkcAuth.get(), 2000); - - expired.await(2, TimeUnit.SECONDS); - connected.await(2, TimeUnit.SECONDS); - - zkcAuth.get().create("/test/key1", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - - rmAll(zkcAuth, "/test"); - } - - /** - * {@link https://issues.apache.org/jira/browse/DL-34}. - */ - @Ignore - @Test(timeout = 60000) - public void testAclAuthSpansExpirationNonRetryableClient() throws Exception { - ZooKeeperClient zkcAuth = clientBuilder().retryPolicy(null).zkAclId("test").build(); - zkcAuth.get().create("/test", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - - CountDownLatch expired = awaitConnectionEvent(KeeperState.Expired, zkcAuth); - CountDownLatch connected = awaitConnectionEvent(KeeperState.SyncConnected, zkcAuth); - - expireZooKeeperSession(zkcAuth.get(), 2000); - - expired.await(2, TimeUnit.SECONDS); - connected.await(2, TimeUnit.SECONDS); - - zkcAuth.get().create("/test/key1", new byte[0], - DistributedLogConstants.EVERYONE_READ_CREATOR_ALL, CreateMode.PERSISTENT); - - rmAll(zkcAuth, "/test"); - } - - static class TestWatcher implements Watcher { - - final List receivedEvents = new ArrayList(); - CountDownLatch latch = new CountDownLatch(0); - - public TestWatcher setLatch(CountDownLatch latch) { - this.latch = latch; - return this; - } - - @Override - public void process(WatchedEvent event) { - if (event.getType() == Event.EventType.NodeDataChanged) { - synchronized (receivedEvents) { - receivedEvents.add(event); - } - latch.countDown(); - } - } - } - - @Test(timeout = 60000) - public void testRegisterUnregisterWatchers() throws Exception { - TestWatcher w1 = new TestWatcher(); - TestWatcher w2 = new TestWatcher(); - - final CountDownLatch latch = new CountDownLatch(2); - w1.setLatch(latch); - w2.setLatch(latch); - - zkc.register(w1); - zkc.register(w2); - - assertEquals(2, zkc.watchers.size()); - - final String zkPath = "/test-register-unregister-watchers"; - - zkc.get().create(zkPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - zkc.get().getData(zkPath, true, new Stat()); - - zkc.get().setData(zkPath, "first-set".getBytes(), -1); - latch.await(); - assertEquals(1, w1.receivedEvents.size()); - assertEquals(zkPath, w1.receivedEvents.get(0).getPath()); - assertEquals(Watcher.Event.EventType.NodeDataChanged, w1.receivedEvents.get(0).getType()); - assertEquals(1, w2.receivedEvents.size()); - assertEquals(zkPath, w2.receivedEvents.get(0).getPath()); - assertEquals(Watcher.Event.EventType.NodeDataChanged, w2.receivedEvents.get(0).getType()); - - final CountDownLatch latch1 = new CountDownLatch(1); - final CountDownLatch latch2 = new CountDownLatch(1); - w1.setLatch(latch1); - w2.setLatch(latch2); - - zkc.unregister(w2); - - assertEquals(1, zkc.watchers.size()); - zkc.get().getData(zkPath, true, new Stat()); - zkc.get().setData(zkPath, "second-set".getBytes(), -1); - latch1.await(); - assertEquals(2, w1.receivedEvents.size()); - assertEquals(zkPath, w1.receivedEvents.get(1).getPath()); - assertEquals(Watcher.Event.EventType.NodeDataChanged, w1.receivedEvents.get(1).getType()); - assertFalse(latch2.await(2, TimeUnit.SECONDS)); - assertEquals(1, w2.receivedEvents.size()); - } - - @Test(timeout = 60000) - public void testExceptionOnWatchers() throws Exception { - TestWatcher w1 = new TestWatcher(); - TestWatcher w2 = new TestWatcher(); - - final CountDownLatch latch = new CountDownLatch(2); - w1.setLatch(latch); - w2.setLatch(latch); - - zkc.register(w1); - zkc.register(w2); - // register bad watcher - zkc.register(new Watcher() { - @Override - public void process(WatchedEvent event) { - throw new NullPointerException("bad watcher returning null"); - } - }); - - assertEquals(3, zkc.watchers.size()); - - final String zkPath = "/test-exception-on-watchers"; - - zkc.get().create(zkPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - zkc.get().getData(zkPath, true, new Stat()); - - zkc.get().setData(zkPath, "first-set".getBytes(), -1); - latch.await(); - assertEquals(1, w1.receivedEvents.size()); - assertEquals(zkPath, w1.receivedEvents.get(0).getPath()); - assertEquals(Watcher.Event.EventType.NodeDataChanged, w1.receivedEvents.get(0).getType()); - assertEquals(1, w2.receivedEvents.size()); - assertEquals(zkPath, w2.receivedEvents.get(0).getPath()); - assertEquals(Watcher.Event.EventType.NodeDataChanged, w2.receivedEvents.get(0).getType()); - } - - @Test(timeout = 60000) - public void testZooKeeperReconnection() throws Exception { - int sessionTimeoutMs = 100; - ZooKeeperClient zkc = clientBuilder(sessionTimeoutMs).zkAclId(null).build(); - ZooKeeper zk = zkc.get(); - long sessionId = zk.getSessionId(); - ZooKeeperClientUtils.expireSession(zkc, zkServers, 2 * sessionTimeoutMs); - ZooKeeper newZk = zkc.get(); - while (!ZooKeeper.States.CONNECTED.equals(newZk.getState())) { - TimeUnit.MILLISECONDS.sleep(sessionTimeoutMs / 2); - } - long newSessionId = newZk.getSessionId(); - assertTrue(newZk == zk); - assertFalse(sessionId == newSessionId); - } - - @Test(timeout = 60000) - public void testZooKeeperReconnectionBlockingRetryThread() throws Exception { - int sessionTimeoutMs = 100; - ZooKeeperClient zkc = clientBuilder(sessionTimeoutMs).zkAclId(null).build(); - ZooKeeper zk = zkc.get(); - assertTrue(zk instanceof org.apache.bookkeeper.zookeeper.ZooKeeperClient); - org.apache.bookkeeper.zookeeper.ZooKeeperClient bkZkc = - (org.apache.bookkeeper.zookeeper.ZooKeeperClient) zk; - // get the connect executor - Field connectExecutorField = bkZkc.getClass().getDeclaredField("connectExecutor"); - connectExecutorField.setAccessible(true); - ExecutorService connectExecutor = (ExecutorService) connectExecutorField.get(bkZkc); - final CountDownLatch latch = new CountDownLatch(1); - // block retry thread in the zookeeper client - connectExecutor.submit(new Runnable() { - @Override - public void run() { - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - }); - ZooKeeperClientUtils.expireSession(zkc, zkServers, 2 * sessionTimeoutMs); - ZooKeeper newZk; - while ((newZk = zkc.get()) == zk) { - TimeUnit.MILLISECONDS.sleep(sessionTimeoutMs / 2); - } - assertEquals(ZooKeeper.States.CONNECTED, newZk.getState()); - } - - @Test(timeout = 60000) - public void testZKTransactionEmptyOps() throws Exception { - CompletableFuture future = new ZKTransaction(zkc).execute(); - assertTrue(future.isDone()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClientBuilder.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClientBuilder.java deleted file mode 100644 index bc41d7f6f48..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClientBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.distributedlog.util.RetryPolicyUtils; - -/** - * The zookeeper client builder used for testing. - */ -public class TestZooKeeperClientBuilder { - - /** - * Return a zookeeper client builder for testing. - * - * @return a zookeeper client builder - */ - public static ZooKeeperClientBuilder newBuilder() { - return ZooKeeperClientBuilder.newBuilder() - .retryPolicy(RetryPolicyUtils.DEFAULT_INFINITE_RETRY_POLICY) - .connectionTimeoutMs(10000) - .sessionTimeoutMs(60000) - .zkAclId(null) - .statsLogger(NullStatsLogger.INSTANCE); - } - - /** - * Create a zookeeper client builder with provided conf for testing. - * - * @param conf distributedlog configuration - * @return zookeeper client builder - */ - public static ZooKeeperClientBuilder newBuilder(DistributedLogConfiguration conf) { - return ZooKeeperClientBuilder.newBuilder() - .retryPolicy(RetryPolicyUtils.DEFAULT_INFINITE_RETRY_POLICY) - .sessionTimeoutMs(conf.getZKSessionTimeoutMilliseconds()) - .zkAclId(conf.getZkAclId()) - .retryThreadCount(conf.getZKClientNumberRetryThreads()) - .requestRateLimit(conf.getZKRequestRateLimit()) - .statsLogger(NullStatsLogger.INSTANCE); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClientUtils.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClientUtils.java deleted file mode 100644 index 3e52d979f13..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClientUtils.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertTrue; - -import com.google.common.base.Stopwatch; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.ZooKeeper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Utilities of {@link org.apache.distributedlog.ZooKeeperClient}. - */ -public class ZooKeeperClientUtils { - - private static final Logger logger = LoggerFactory.getLogger(ZooKeeperClientUtils.class); - - /** - * Expire given zookeeper client's session. - * - * @param zkc - * zookeeper client - * @param zkServers - * zookeeper servers - * @param timeout - * timeout - * @throws Exception - */ - public static void expireSession(ZooKeeperClient zkc, String zkServers, int timeout) - throws Exception { - final CountDownLatch expireLatch = new CountDownLatch(1); - final CountDownLatch latch = new CountDownLatch(1); - ZooKeeper oldZk = zkc.get(); - oldZk.exists("/", new Watcher() { - @Override - public void process(WatchedEvent event) { - logger.debug("Receive event : {}", event); - if (event.getType() == Event.EventType.None - && event.getState() == Event.KeeperState.Expired) { - expireLatch.countDown(); - } - } - }); - ZooKeeper newZk = new ZooKeeper(zkServers, timeout, new Watcher() { - @Override - public void process(WatchedEvent event) { - if (Event.EventType.None == event.getType() - && Event.KeeperState.SyncConnected == event.getState()) { - latch.countDown(); - } - } - }, oldZk.getSessionId(), oldZk.getSessionPasswd()); - if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { - throw KeeperException.create(KeeperException.Code.CONNECTIONLOSS); - } - newZk.close(); - - boolean done = false; - Stopwatch expireWait = Stopwatch.createStarted(); - while (!done && expireWait.elapsed(TimeUnit.MILLISECONDS) < timeout * 2) { - try { - zkc.get().exists("/", false); - done = true; - } catch (KeeperException ke) { - done = (ke.code() == KeeperException.Code.SESSIONEXPIRED); - } - } - - assertTrue("Client should receive session expired event.", - expireLatch.await(timeout, TimeUnit.MILLISECONDS)); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClusterTestCase.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClusterTestCase.java deleted file mode 100644 index a3d59ef210e..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/ZooKeeperClusterTestCase.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import java.io.File; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.shims.zk.ZooKeeperServerShim; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.AfterClass; -import org.junit.BeforeClass; - - -/** - * ZooKeeperClusterTestCase. - */ -@Slf4j -public class ZooKeeperClusterTestCase { - - static { - // org.apache.zookeeper.test.ClientBase uses FourLetterWordMain, from 3.5.3 four letter words - // are disabled by default due to security reasons - System.setProperty("zookeeper.4lw.commands.whitelist", "*"); - } - - protected static File zkDir; - protected static ZooKeeperServerShim zks; - protected static String zkServers; - protected static int zkPort; - - @BeforeClass - public static void setupZooKeeper() throws Exception { - zkDir = IOUtils.createTempDir("zookeeper", ZooKeeperClusterTestCase.class.getName()); - Pair serverAndPort = LocalDLMEmulator.runZookeeperOnAnyPort(zkDir); - zks = serverAndPort.getLeft(); - zkPort = serverAndPort.getRight(); - zkServers = "127.0.0.1:" + zkPort; - - log.info("--- Setup zookeeper at {} ---", zkServers); - } - - @AfterClass - public static void shutdownZooKeeper() throws Exception { - log.info("--- Shutdown zookeeper at {} ---", zkServers); - zks.stop(); - if (null != zkDir) { - FileUtils.forceDeleteOnExit(zkDir); - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControl.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControl.java deleted file mode 100644 index 4e7628b7463..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControl.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.acl; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.net.URI; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.distributedlog.impl.acl.ZKAccessControl; -import org.apache.distributedlog.thrift.AccessControlEntry; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - - - - -/** - * TestZKAccessControl. - */ -public class TestZKAccessControl extends ZooKeeperClusterTestCase { - - private ZooKeeperClient zkc; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createURI("/")) - .build(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - } - - private URI createURI(String path) { - return URI.create("distributedlog://127.0.0.1:" + zkPort + path); - } - - @Test(timeout = 60000) - public void testCreateZKAccessControl() throws Exception { - AccessControlEntry ace = new AccessControlEntry(); - ace.setDenyWrite(true); - String zkPath = "/create-zk-access-control"; - ZKAccessControl zkac = new ZKAccessControl(ace, zkPath); - Utils.ioResult(zkac.create(zkc)); - - ZKAccessControl readZKAC = Utils.ioResult(ZKAccessControl.read(zkc, zkPath, null)); - assertEquals(zkac, readZKAC); - - ZKAccessControl another = new ZKAccessControl(ace, zkPath); - try { - FutureUtils.result(another.create(zkc)); - } catch (KeeperException.NodeExistsException ke) { - // expected - } - } - - @Test(timeout = 60000) - public void testDeleteZKAccessControl() throws Exception { - String zkPath = "/delete-zk-access-control"; - - AccessControlEntry ace = new AccessControlEntry(); - ace.setDenyDelete(true); - - ZKAccessControl zkac = new ZKAccessControl(ace, zkPath); - Utils.ioResult(zkac.create(zkc)); - - ZKAccessControl readZKAC = Utils.ioResult(ZKAccessControl.read(zkc, zkPath, null)); - assertEquals(zkac, readZKAC); - - Utils.ioResult(ZKAccessControl.delete(zkc, zkPath)); - - try { - FutureUtils.result(ZKAccessControl.read(zkc, zkPath, null)); - } catch (KeeperException.NoNodeException nne) { - // expected. - } - Utils.ioResult(ZKAccessControl.delete(zkc, zkPath)); - } - - @Test(timeout = 60000) - public void testEmptyZKAccessControl() throws Exception { - String zkPath = "/empty-access-control"; - - zkc.get().create(zkPath, new byte[0], zkc.getDefaultACL(), CreateMode.PERSISTENT); - - ZKAccessControl readZKAC = Utils.ioResult(ZKAccessControl.read(zkc, zkPath, null)); - - assertEquals(zkPath, readZKAC.getZKPath()); - assertEquals(ZKAccessControl.DEFAULT_ACCESS_CONTROL_ENTRY, readZKAC.getAccessControlEntry()); - assertTrue(ZKAccessControl.DEFAULT_ACCESS_CONTROL_ENTRY == readZKAC.getAccessControlEntry()); - } - - @Test(timeout = 60000) - public void testCorruptedZKAccessControl() throws Exception { - String zkPath = "/corrupted-zk-access-control"; - - zkc.get().create(zkPath, "corrupted-data".getBytes(UTF_8), zkc.getDefaultACL(), CreateMode.PERSISTENT); - - try { - Utils.ioResult(ZKAccessControl.read(zkc, zkPath, null)); - } catch (ZKAccessControl.CorruptedAccessControlException cace) { - // expected - } - } - - @Test(timeout = 60000) - public void testUpdateZKAccessControl() throws Exception { - String zkPath = "/update-zk-access-control"; - - AccessControlEntry ace = new AccessControlEntry(); - ace.setDenyDelete(true); - - ZKAccessControl zkac = new ZKAccessControl(ace, zkPath); - Utils.ioResult(zkac.create(zkc)); - - ZKAccessControl readZKAC = Utils.ioResult(ZKAccessControl.read(zkc, zkPath, null)); - assertEquals(zkac, readZKAC); - - ace.setDenyRelease(true); - ZKAccessControl newZKAC = new ZKAccessControl(ace, zkPath); - Utils.ioResult(newZKAC.update(zkc)); - ZKAccessControl readZKAC2 = Utils.ioResult(ZKAccessControl.read(zkc, zkPath, null)); - assertEquals(newZKAC, readZKAC2); - - try { - FutureUtils.result(readZKAC.update(zkc)); - } catch (KeeperException.BadVersionException bve) { - // expected - } - readZKAC2.getAccessControlEntry().setDenyTruncate(true); - Utils.ioResult(readZKAC2.update(zkc)); - ZKAccessControl readZKAC3 = Utils.ioResult(ZKAccessControl.read(zkc, zkPath, null)); - assertEquals(readZKAC2, readZKAC3); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControlManager.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControlManager.java deleted file mode 100644 index 940a18dcda6..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/acl/TestZKAccessControlManager.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.acl; - -import static org.junit.Assert.assertEquals; - -import java.net.URI; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClientUtils; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.distributedlog.impl.acl.ZKAccessControl; -import org.apache.distributedlog.impl.acl.ZKAccessControlManager; -import org.apache.distributedlog.thrift.AccessControlEntry; -import org.apache.distributedlog.util.Utils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * TestZKAccessControlManager. - */ -public class TestZKAccessControlManager extends ZooKeeperClusterTestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestZKAccessControlManager.class); - - private DistributedLogConfiguration conf; - private ZooKeeperClient zkc; - private ScheduledExecutorService executorService; - - private URI createURI(String path) { - return URI.create("distributedlog://127.0.0.1:" + zkPort + path); - } - - @Before - public void setup() throws Exception { - executorService = Executors.newSingleThreadScheduledExecutor(); - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createURI("/")) - .build(); - conf = new DistributedLogConfiguration(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - executorService.shutdown(); - } - - void setACL(ZKAccessControl accessControl) throws Exception { - String zkPath = accessControl.getZKPath(); - if (null == zkc.get().exists(zkPath, false)) { - accessControl.create(zkc); - } else { - accessControl.update(zkc); - } - } - - static void verifyStreamPermissions(ZKAccessControlManager zkcm, - String stream, - boolean allowWrite, - boolean allowTruncate, - boolean allowRelease, - boolean allowDelete, - boolean allowAcquire) throws Exception { - assertEquals(allowWrite, zkcm.allowWrite(stream)); - assertEquals(allowTruncate, zkcm.allowTruncate(stream)); - assertEquals(allowRelease, zkcm.allowRelease(stream)); - assertEquals(allowDelete, zkcm.allowDelete(stream)); - assertEquals(allowAcquire, zkcm.allowAcquire(stream)); - } - - @Test(timeout = 60000) - public void testZKAccessControlManager() throws Exception { - String zkRootPath = "/test-zk-access-control-manager"; - String stream1 = "test-acm-1"; - String stream2 = "test-acm-2"; - logger.info("Creating ACL Manager for {}", zkRootPath); - ZKAccessControlManager zkcm = new ZKAccessControlManager(conf, zkc, zkRootPath, executorService); - logger.info("Created ACL Manager for {}", zkRootPath); - try { - verifyStreamPermissions(zkcm, stream1, true, true, true, true, true); - - // create stream1 (denyDelete = true) - String zkPath1 = zkRootPath + "/" + stream1; - AccessControlEntry ace1 = new AccessControlEntry(); - ace1.setDenyDelete(true); - ZKAccessControl accessControl1 = new ZKAccessControl(ace1, zkPath1); - setACL(accessControl1); - logger.info("Create ACL for stream {} : {}", stream1, accessControl1); - while (zkcm.allowDelete(stream1)) { - Thread.sleep(100); - } - verifyStreamPermissions(zkcm, stream1, true, true, true, false, true); - - // update stream1 (denyDelete = false, denyWrite = true) - ace1 = new AccessControlEntry(); - ace1.setDenyWrite(true); - accessControl1 = new ZKAccessControl(ace1, zkPath1); - setACL(accessControl1); - logger.info("Update ACL for stream {} : {}", stream1, accessControl1); - - // create stream2 (denyTruncate = true) - String zkPath2 = zkRootPath + "/" + stream2; - AccessControlEntry ace2 = new AccessControlEntry(); - ace2.setDenyTruncate(true); - ZKAccessControl accessControl2 = new ZKAccessControl(ace2, zkPath2); - setACL(accessControl2); - logger.info("Create ACL for stream {} : {}", stream2, accessControl2); - while (zkcm.allowWrite(stream1)) { - Thread.sleep(100); - } - while (zkcm.allowTruncate(stream2)) { - Thread.sleep(100); - } - - verifyStreamPermissions(zkcm, stream1, false, true, true, true, true); - verifyStreamPermissions(zkcm, stream2, true, false, true, true, true); - - // delete stream2 - Utils.ioResult(ZKAccessControl.delete(zkc, zkPath2)); - logger.info("Delete ACL for stream {}", stream2); - while (!zkcm.allowTruncate(stream2)) { - Thread.sleep(100); - } - - verifyStreamPermissions(zkcm, stream1, false, true, true, true, true); - verifyStreamPermissions(zkcm, stream2, true, true, true, true, true); - - // expire session - ZooKeeperClientUtils.expireSession(zkc, zkServers, 1000); - - // update stream1 (denyDelete = false, denyWrite = true) - ace1 = new AccessControlEntry(); - ace1.setDenyRelease(true); - accessControl1 = new ZKAccessControl(ace1, zkPath1); - setACL(accessControl1); - logger.info("Update ACL for stream {} : {}", stream1, accessControl1); - - // create stream2 (denyTruncate = true) - ace2 = new AccessControlEntry(); - ace2.setDenyAcquire(true); - accessControl2 = new ZKAccessControl(ace2, zkPath2); - setACL(accessControl2); - logger.info("Created ACL for stream {} again : {}", stream2, accessControl2); - - while (zkcm.allowRelease(stream1)) { - Thread.sleep(100); - } - while (zkcm.allowAcquire(stream2)) { - Thread.sleep(100); - } - - verifyStreamPermissions(zkcm, stream1, true, true, false, true, true); - verifyStreamPermissions(zkcm, stream2, true, true, true, true, false); - } finally { - zkcm.close(); - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDLCK.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDLCK.java deleted file mode 100644 index bed16ad5c0f..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDLCK.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.admin; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.LogSegmentMetadata; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.common.util.SchedulerUtils; -import org.apache.distributedlog.metadata.DryrunLogSegmentMetadataStoreUpdater; -import org.apache.distributedlog.metadata.LogSegmentMetadataStoreUpdater; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - - - -/** - * TestDLCK. - */ -public class TestDLCK extends TestDistributedLogBase { - - static final Logger LOG = LoggerFactory.getLogger(TestDLCK.class); - - protected static DistributedLogConfiguration conf = - new DistributedLogConfiguration().setLockTimeout(10) - .setEnableLedgerAllocatorPool(true).setLedgerAllocatorPoolName("test"); - - private ZooKeeperClient zkc; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder - .newBuilder() - .uri(createDLMURI("/")) - .build(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - } - - static Map getLogSegments(DistributedLogManager dlm) throws Exception { - Map logSegmentMap = - new HashMap(); - List segments = dlm.getLogSegments(); - for (LogSegmentMetadata segment : segments) { - logSegmentMap.put(segment.getLogSegmentSequenceNumber(), segment); - } - return logSegmentMap; - } - - static void verifyLogSegment(Map segments, - DLSN lastDLSN, long logSegmentSequenceNumber, - int recordCount, long lastTxId) { - LogSegmentMetadata segment = segments.get(logSegmentSequenceNumber); - assertNotNull(segment); - assertEquals(lastDLSN, segment.getLastDLSN()); - assertEquals(recordCount, segment.getRecordCount()); - assertEquals(lastTxId, segment.getLastTxId()); - } - - @Test(timeout = 60000) - @SuppressWarnings("deprecation") - public void testCheckAndRepairDLNamespace() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.loadConf(conf); - confLocal.setImmediateFlushEnabled(true); - confLocal.setOutputBufferSize(0); - confLocal.setLogSegmentSequenceNumberValidationEnabled(false); - confLocal.setLogSegmentCacheEnabled(false); - URI uri = createDLMURI("/check-and-repair-dl-namespace"); - zkc.get().create(uri.getPath(), new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(confLocal) - .uri(uri) - .build(); - OrderedScheduler scheduler = OrderedScheduler.newSchedulerBuilder() - .name("dlck-tool") - .numThreads(1) - .build(); - ExecutorService executorService = Executors.newCachedThreadPool(); - - String streamName = "check-and-repair-dl-namespace"; - - // Create completed log segments - DistributedLogManager dlm = namespace.openLog(streamName); - DLMTestUtil.injectLogSegmentWithLastDLSN(dlm, confLocal, 1L, 1L, 10, false); - DLMTestUtil.injectLogSegmentWithLastDLSN(dlm, confLocal, 2L, 11L, 10, true); - DLMTestUtil.injectLogSegmentWithLastDLSN(dlm, confLocal, 3L, 21L, 10, false); - DLMTestUtil.injectLogSegmentWithLastDLSN(dlm, confLocal, 4L, 31L, 10, true); - - // dryrun - DistributedLogAdmin.checkAndRepairDLNamespace( - uri, - namespace, - new DryrunLogSegmentMetadataStoreUpdater(confLocal, getLogSegmentMetadataStore(namespace)), - scheduler, - false, - false); - - Map segments = getLogSegments(dlm); - LOG.info("segments after drynrun {}", segments); - verifyLogSegment(segments, new DLSN(1L, 18L, 0L), 1L, 10, 10L); - verifyLogSegment(segments, new DLSN(2L, 16L, 0L), 2L, 9, 19L); - verifyLogSegment(segments, new DLSN(3L, 18L, 0L), 3L, 10, 30L); - verifyLogSegment(segments, new DLSN(4L, 16L, 0L), 4L, 9, 39L); - - // check and repair - DistributedLogAdmin.checkAndRepairDLNamespace( - uri, - namespace, - LogSegmentMetadataStoreUpdater.createMetadataUpdater(confLocal, getLogSegmentMetadataStore(namespace)), - scheduler, - false, - false); - - segments = getLogSegments(dlm); - LOG.info("segments after repair {}", segments); - verifyLogSegment(segments, new DLSN(1L, 18L, 0L), 1L, 10, 10L); - verifyLogSegment(segments, new DLSN(2L, 18L, 0L), 2L, 10, 20L); - verifyLogSegment(segments, new DLSN(3L, 18L, 0L), 3L, 10, 30L); - verifyLogSegment(segments, new DLSN(4L, 18L, 0L), 4L, 10, 40L); - - dlm.close(); - SchedulerUtils.shutdownScheduler(executorService, 5, TimeUnit.MINUTES); - namespace.close(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java deleted file mode 100644 index e4c9a77ce0f..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.admin; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import java.net.URI; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.LogRecord; -import org.apache.distributedlog.LogRecordWithDLSN; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.exceptions.UnexpectedException; -import org.apache.distributedlog.metadata.DryrunLogSegmentMetadataStoreUpdater; -import org.apache.distributedlog.metadata.LogSegmentMetadataStoreUpdater; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * TestDistributedLogAdmin. - */ -public class TestDistributedLogAdmin extends TestDistributedLogBase { - - static final Logger LOG = LoggerFactory.getLogger(TestDistributedLogAdmin.class); - - private ZooKeeperClient zooKeeperClient; - - @Before - public void setup() throws Exception { - zooKeeperClient = TestZooKeeperClientBuilder - .newBuilder() - .uri(createDLMURI("/")) - .build(); - conf.setTraceReadAheadMetadataChanges(true); - } - - @After - public void teardown() throws Exception { - zooKeeperClient.close(); - } - - @FlakyTest("https://issues.apache.org/jira/browse/DL-44") - @SuppressWarnings("deprecation") - public void testChangeSequenceNumber() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setLogSegmentSequenceNumberValidationEnabled(false); - confLocal.setLogSegmentCacheEnabled(false); - - DistributedLogConfiguration readConf = new DistributedLogConfiguration(); - readConf.addConfiguration(conf); - readConf.setLogSegmentCacheEnabled(false); - readConf.setLogSegmentSequenceNumberValidationEnabled(true); - - URI uri = createDLMURI("/change-sequence-number"); - zooKeeperClient.get().create(uri.getPath(), new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(confLocal) - .uri(uri) - .build(); - Namespace readNamespace = NamespaceBuilder.newBuilder() - .conf(readConf) - .uri(uri) - .build(); - - String streamName = "change-sequence-number"; - - // create completed log segments - DistributedLogManager dlm = namespace.openLog(streamName); - DLMTestUtil.generateCompletedLogSegments(dlm, confLocal, 4, 10); - DLMTestUtil.injectLogSegmentWithGivenLogSegmentSeqNo(dlm, confLocal, 5, 41, false, 10, true); - dlm.close(); - - // create a reader - DistributedLogManager readDLM = readNamespace.openLog(streamName); - AsyncLogReader reader = readDLM.getAsyncLogReader(DLSN.InitialDLSN); - - // read the records - long expectedTxId = 1L; - DLSN lastDLSN = DLSN.InitialDLSN; - for (int i = 0; i < 4 * 10; i++) { - LogRecordWithDLSN record = Utils.ioResult(reader.readNext()); - assertNotNull(record); - DLMTestUtil.verifyLogRecord(record); - assertEquals(expectedTxId, record.getTransactionId()); - expectedTxId++; - lastDLSN = record.getDlsn(); - } - - LOG.info("Injecting bad log segment '3'"); - - dlm = namespace.openLog(streamName); - DLMTestUtil.injectLogSegmentWithGivenLogSegmentSeqNo(dlm, confLocal, 3L, 5 * 10 + 1, true, 10, false); - - LOG.info("Injected bad log segment '3'"); - - // there isn't records should be read - CompletableFuture readFuture = reader.readNext(); - try { - LogRecordWithDLSN record = Utils.ioResult(readFuture); - fail("Should fail reading next record " - + record - + " when there is a corrupted log segment"); - } catch (UnexpectedException ue) { - // expected - } - - LOG.info("Dryrun fix inprogress segment that has lower sequence number"); - - // Dryrun - DistributedLogAdmin.fixInprogressSegmentWithLowerSequenceNumber(namespace, - new DryrunLogSegmentMetadataStoreUpdater(confLocal, - getLogSegmentMetadataStore(namespace)), streamName, false, false); - - try { - reader = readDLM.getAsyncLogReader(lastDLSN); - Utils.ioResult(reader.readNext()); - fail("Should fail reading next when there is a corrupted log segment"); - } catch (UnexpectedException ue) { - // expected - } - - LOG.info("Actual run fix inprogress segment that has lower sequence number"); - - // Actual run - DistributedLogAdmin.fixInprogressSegmentWithLowerSequenceNumber(namespace, - LogSegmentMetadataStoreUpdater.createMetadataUpdater(confLocal, - getLogSegmentMetadataStore(namespace)), streamName, false, false); - - // be able to read more after fix - reader = readDLM.getAsyncLogReader(lastDLSN); - // skip the first record - Utils.ioResult(reader.readNext()); - readFuture = reader.readNext(); - - expectedTxId = 51L; - LogRecord record = Utils.ioResult(readFuture); - assertNotNull(record); - DLMTestUtil.verifyLogRecord(record); - assertEquals(expectedTxId, record.getTransactionId()); - expectedTxId++; - - for (int i = 1; i < 10; i++) { - record = Utils.ioResult(reader.readNext()); - assertNotNull(record); - DLMTestUtil.verifyLogRecord(record); - assertEquals(expectedTxId, record.getTransactionId()); - expectedTxId++; - } - - Utils.close(reader); - readDLM.close(); - - dlm.close(); - namespace.close(); - readNamespace.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java deleted file mode 100644 index 23d958dfc6c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.bk; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.net.URI; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.distributedlog.BookKeeperClient; -import org.apache.distributedlog.BookKeeperClientBuilder; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.bk.SimpleLedgerAllocator.AllocationException; -import org.apache.distributedlog.bk.SimpleLedgerAllocator.Phase; -import org.apache.distributedlog.exceptions.ZKException; -import org.apache.distributedlog.util.Transaction.OpListener; -import org.apache.distributedlog.util.Utils; -import org.apache.distributedlog.zk.DefaultZKOp; -import org.apache.distributedlog.zk.ZKTransaction; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.Op; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * TestLedgerAllocator. - */ -public class TestLedgerAllocator extends TestDistributedLogBase { - - private static final Logger logger = LoggerFactory.getLogger(TestLedgerAllocator.class); - - private static final String ledgersPath = "/ledgers"; - private static final OpListener NULL_LISTENER = new OpListener() { - @Override - public void onCommit(LedgerHandle r) { - // no-op - } - - @Override - public void onAbort(Throwable t) { - // no-op - } - }; - - @Rule - public TestName runtime = new TestName(); - - private ZooKeeperClient zkc; - private BookKeeperClient bkc; - private DistributedLogConfiguration dlConf = new DistributedLogConfiguration(); - - private URI createURI(String path) { - return URI.create("distributedlog://" + zkServers + path); - } - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createURI("/")) - .zkServers(zkServers) - .build(); - bkc = BookKeeperClientBuilder.newBuilder().name("bkc") - .dlConfig(dlConf).ledgersPath(ledgersPath).zkc(zkc).build(); - } - - @After - public void teardown() throws Exception { - bkc.close(); - zkc.close(); - } - - private QuorumConfigProvider newQuorumConfigProvider(DistributedLogConfiguration conf) { - return new ImmutableQuorumConfigProvider(conf.getQuorumConfig()); - } - - private ZKTransaction newTxn() { - return new ZKTransaction(zkc); - } - - private SimpleLedgerAllocator createAllocator(String allocationPath) throws Exception { - return createAllocator(allocationPath, dlConf); - } - - private SimpleLedgerAllocator createAllocator(String allocationPath, - DistributedLogConfiguration conf) throws Exception { - return createAllocator(allocationPath, conf, null); - } - - private SimpleLedgerAllocator createAllocator(String allocationPath, - DistributedLogConfiguration conf, - LedgerMetadata ledgerMetadata) throws Exception { - return Utils.ioResult(SimpleLedgerAllocator.of(allocationPath, null, - newQuorumConfigProvider(conf), zkc, bkc, ledgerMetadata)); - } - - @FlakyTest("https://issues.apache.org/jira/browse/DL-43") - public void testAllocation() throws Exception { - String allocationPath = "/allocation1"; - SimpleLedgerAllocator allocator = createAllocator(allocationPath); - allocator.allocate(); - ZKTransaction txn = newTxn(); - LedgerHandle lh = Utils.ioResult(allocator.tryObtain(txn, NULL_LISTENER)); - logger.info("Try obtaining ledger handle {}", lh.getId()); - byte[] data = zkc.get().getData(allocationPath, false, null); - assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8))); - txn.addOp(DefaultZKOp.of(Op.setData("/unexistedpath", "data".getBytes(UTF_8), -1), null)); - try { - Utils.ioResult(txn.execute()); - fail("Should fail the transaction when setting unexisted path"); - } catch (ZKException ke) { - // expected - logger.info("Should fail on executing transaction when setting unexisted path", ke); - } - data = zkc.get().getData(allocationPath, false, null); - assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8))); - - // Create new transaction to obtain the ledger again. - txn = newTxn(); - // we could obtain the ledger if it was obtained - LedgerHandle newLh = Utils.ioResult(allocator.tryObtain(txn, NULL_LISTENER)); - assertEquals(lh.getId(), newLh.getId()); - Utils.ioResult(txn.execute()); - data = zkc.get().getData(allocationPath, false, null); - assertEquals(0, data.length); - Utils.close(allocator); - } - - @Test(timeout = 60000) - public void testBadVersionOnTwoAllocators() throws Exception { - String allocationPath = "/allocation-bad-version"; - zkc.get().create(allocationPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - Stat stat = new Stat(); - byte[] data = zkc.get().getData(allocationPath, false, stat); - Versioned allocationData = new Versioned(data, new LongVersion(stat.getVersion())); - - SimpleLedgerAllocator allocator1 = - new SimpleLedgerAllocator(allocationPath, allocationData, newQuorumConfigProvider(dlConf), zkc, bkc); - SimpleLedgerAllocator allocator2 = - new SimpleLedgerAllocator(allocationPath, allocationData, newQuorumConfigProvider(dlConf), zkc, bkc); - allocator1.allocate(); - // wait until allocated - ZKTransaction txn1 = newTxn(); - LedgerHandle lh = Utils.ioResult(allocator1.tryObtain(txn1, NULL_LISTENER)); - allocator2.allocate(); - ZKTransaction txn2 = newTxn(); - try { - Utils.ioResult(allocator2.tryObtain(txn2, NULL_LISTENER)); - fail("Should fail allocating on second allocator as allocator1 is starting allocating something."); - } catch (ZKException ke) { - assertEquals(KeeperException.Code.BADVERSION, ke.getKeeperExceptionCode()); - } - Utils.ioResult(txn1.execute()); - Utils.close(allocator1); - Utils.close(allocator2); - - long eid = lh.addEntry("hello world".getBytes()); - lh.close(); - LedgerHandle readLh = bkc.get().openLedger(lh.getId(), - BookKeeper.DigestType.CRC32, dlConf.getBKDigestPW().getBytes()); - Enumeration entries = readLh.readEntries(eid, eid); - int i = 0; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertEquals("hello world", new String(entry.getEntry(), UTF_8)); - ++i; - } - assertEquals(1, i); - } - - @Test(timeout = 60000) - public void testAllocatorWithoutEnoughBookies() throws Exception { - String allocationPath = "/allocator-without-enough-bookies"; - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setEnsembleSize(numBookies * 2); - confLocal.setWriteQuorumSize(numBookies * 2); - - SimpleLedgerAllocator allocator1 = createAllocator(allocationPath, confLocal); - allocator1.allocate(); - ZKTransaction txn1 = newTxn(); - - try { - Utils.ioResult(allocator1.tryObtain(txn1, NULL_LISTENER)); - fail("Should fail allocating ledger if there aren't enough bookies"); - } catch (AllocationException ioe) { - // expected - assertEquals(Phase.ERROR, ioe.getPhase()); - } - byte[] data = zkc.get().getData(allocationPath, false, null); - assertEquals(0, data.length); - } - - @Test(timeout = 60000) - public void testSuccessAllocatorShouldDeleteUnusedledger() throws Exception { - String allocationPath = "/allocation-delete-unused-ledger"; - zkc.get().create(allocationPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - Stat stat = new Stat(); - byte[] data = zkc.get().getData(allocationPath, false, stat); - - Versioned allocationData = new Versioned(data, new LongVersion(stat.getVersion())); - - SimpleLedgerAllocator allocator1 = - new SimpleLedgerAllocator(allocationPath, allocationData, newQuorumConfigProvider(dlConf), zkc, bkc); - allocator1.allocate(); - // wait until allocated - ZKTransaction txn1 = newTxn(); - LedgerHandle lh1 = Utils.ioResult(allocator1.tryObtain(txn1, NULL_LISTENER)); - - // Second allocator kicks in - stat = new Stat(); - data = zkc.get().getData(allocationPath, false, stat); - allocationData = new Versioned(data, new LongVersion(stat.getVersion())); - SimpleLedgerAllocator allocator2 = - new SimpleLedgerAllocator(allocationPath, allocationData, newQuorumConfigProvider(dlConf), zkc, bkc); - allocator2.allocate(); - // wait until allocated - ZKTransaction txn2 = newTxn(); - LedgerHandle lh2 = Utils.ioResult(allocator2.tryObtain(txn2, NULL_LISTENER)); - - // should fail to commit txn1 as version is changed by second allocator - try { - Utils.ioResult(txn1.execute()); - fail("Should fail commit obtaining ledger handle from first allocator" - + " as allocator is modified by second allocator."); - } catch (ZKException ke) { - // as expected - } - Utils.ioResult(txn2.execute()); - Utils.close(allocator1); - Utils.close(allocator2); - - // ledger handle should be deleted - try { - lh1.close(); - fail("LedgerHandle allocated by allocator1 should be deleted."); - } catch (BKException bke) { - // as expected - } - try { - bkc.get().openLedger(lh1.getId(), BookKeeper.DigestType.CRC32, dlConf.getBKDigestPW().getBytes()); - fail("LedgerHandle allocated by allocator1 should be deleted."); - } catch (BKException.BKNoSuchLedgerExistsOnMetadataServerException nslee) { - // as expected - } - long eid = lh2.addEntry("hello world".getBytes()); - lh2.close(); - LedgerHandle readLh = bkc.get().openLedger(lh2.getId(), - BookKeeper.DigestType.CRC32, dlConf.getBKDigestPW().getBytes()); - Enumeration entries = readLh.readEntries(eid, eid); - int i = 0; - while (entries.hasMoreElements()) { - LedgerEntry entry = entries.nextElement(); - assertEquals("hello world", new String(entry.getEntry(), UTF_8)); - ++i; - } - assertEquals(1, i); - } - - @Test(timeout = 60000) - public void testCloseAllocatorDuringObtaining() throws Exception { - String allocationPath = "/allocation2"; - SimpleLedgerAllocator allocator = createAllocator(allocationPath); - allocator.allocate(); - ZKTransaction txn = newTxn(); - // close during obtaining ledger. - LedgerHandle lh = Utils.ioResult(allocator.tryObtain(txn, NULL_LISTENER)); - Utils.close(allocator); - byte[] data = zkc.get().getData(allocationPath, false, null); - assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8))); - // the ledger is not deleted - bkc.get().openLedger(lh.getId(), BookKeeper.DigestType.CRC32, - dlConf.getBKDigestPW().getBytes(UTF_8)); - } - - @FlakyTest("https://issues.apache.org/jira/browse/DL-26") - public void testCloseAllocatorAfterConfirm() throws Exception { - String allocationPath = "/allocation2"; - SimpleLedgerAllocator allocator = createAllocator(allocationPath); - allocator.allocate(); - ZKTransaction txn = newTxn(); - // close during obtaining ledger. - LedgerHandle lh = Utils.ioResult(allocator.tryObtain(txn, NULL_LISTENER)); - Utils.ioResult(txn.execute()); - Utils.close(allocator); - byte[] data = zkc.get().getData(allocationPath, false, null); - assertEquals(0, data.length); - // the ledger is not deleted. - bkc.get().openLedger(lh.getId(), BookKeeper.DigestType.CRC32, - dlConf.getBKDigestPW().getBytes(UTF_8)); - } - - @Test(timeout = 60000) - public void testCloseAllocatorAfterAbort() throws Exception { - String allocationPath = "/allocation3"; - SimpleLedgerAllocator allocator = createAllocator(allocationPath); - allocator.allocate(); - ZKTransaction txn = newTxn(); - // close during obtaining ledger. - LedgerHandle lh = Utils.ioResult(allocator.tryObtain(txn, NULL_LISTENER)); - txn.addOp(DefaultZKOp.of(Op.setData("/unexistedpath", "data".getBytes(UTF_8), -1), null)); - try { - Utils.ioResult(txn.execute()); - fail("Should fail the transaction when setting unexisted path"); - } catch (ZKException ke) { - // expected - } - Utils.close(allocator); - byte[] data = zkc.get().getData(allocationPath, false, null); - assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8))); - // the ledger is not deleted. - bkc.get().openLedger(lh.getId(), BookKeeper.DigestType.CRC32, - dlConf.getBKDigestPW().getBytes(UTF_8)); - } - - @Test(timeout = 60000) - public void testConcurrentAllocation() throws Exception { - String allcationPath = "/" + runtime.getMethodName(); - SimpleLedgerAllocator allocator = createAllocator(allcationPath); - allocator.allocate(); - ZKTransaction txn1 = newTxn(); - CompletableFuture obtainFuture1 = allocator.tryObtain(txn1, NULL_LISTENER); - ZKTransaction txn2 = newTxn(); - CompletableFuture obtainFuture2 = allocator.tryObtain(txn2, NULL_LISTENER); - assertTrue(obtainFuture2.isDone()); - assertTrue(obtainFuture2.isCompletedExceptionally()); - try { - Utils.ioResult(obtainFuture2); - fail("Should fail the concurrent obtain since there is already a transaction obtaining the ledger handle"); - } catch (SimpleLedgerAllocator.ConcurrentObtainException cbe) { - // expected - } - } - - @Test(timeout = 60000) - public void testObtainMultipleLedgers() throws Exception { - String allocationPath = "/" + runtime.getMethodName(); - SimpleLedgerAllocator allocator = createAllocator(allocationPath); - int numLedgers = 10; - Set allocatedLedgers = new HashSet(); - for (int i = 0; i < numLedgers; i++) { - allocator.allocate(); - ZKTransaction txn = newTxn(); - LedgerHandle lh = Utils.ioResult(allocator.tryObtain(txn, NULL_LISTENER)); - Utils.ioResult(txn.execute()); - allocatedLedgers.add(lh); - } - assertEquals(numLedgers, allocatedLedgers.size()); - } - - @Test(timeout = 60000) - public void testAllocationWithMetadata() throws Exception { - String allocationPath = "/" + runtime.getMethodName(); - - String application = "testApplicationMetadata"; - String component = "testComponentMetadata"; - String custom = "customMetadata"; - LedgerMetadata ledgerMetadata = new LedgerMetadata(); - ledgerMetadata.setApplication(application); - ledgerMetadata.setComponent(component); - ledgerMetadata.addCustomMetadata("custom", custom); - - SimpleLedgerAllocator allocator = createAllocator(allocationPath, dlConf, ledgerMetadata); - allocator.allocate(); - - ZKTransaction txn = newTxn(); - LedgerHandle lh = Utils.ioResult(allocator.tryObtain(txn, NULL_LISTENER)); - Map customMeta = lh.getCustomMetadata(); - assertEquals(application, new String(customMeta.get("application"), UTF_8)); - assertEquals(component, new String(customMeta.get("component"), UTF_8)); - assertEquals(custom, new String(customMeta.get("custom"), UTF_8)); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocatorPool.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocatorPool.java deleted file mode 100644 index 1528518d08d..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocatorPool.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.bk; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.io.IOException; -import java.net.URI; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.distributedlog.BookKeeperClient; -import org.apache.distributedlog.BookKeeperClientBuilder; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.util.Transaction.OpListener; -import org.apache.distributedlog.util.Utils; -import org.apache.distributedlog.zk.ZKTransaction; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - - -/** - * TestLedgerAllocatorPool. - */ -public class TestLedgerAllocatorPool extends TestDistributedLogBase { - - private static final Logger logger = LoggerFactory.getLogger(TestLedgerAllocatorPool.class); - - private static final String ledgersPath = "/ledgers"; - private static final OpListener NULL_LISTENER = new OpListener() { - @Override - public void onCommit(LedgerHandle r) { - // no-op - } - - @Override - public void onAbort(Throwable t) { - // no-op - } - }; - - @Rule - public TestName runtime = new TestName(); - - private ZooKeeperClient zkc; - private BookKeeperClient bkc; - private DistributedLogConfiguration dlConf = new DistributedLogConfiguration(); - private ScheduledExecutorService allocationExecutor; - - private URI createURI(String path) { - return URI.create("distributedlog://" + zkServers + path); - } - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createURI("/")) - .build(); - bkc = BookKeeperClientBuilder.newBuilder().name("bkc") - .dlConfig(dlConf).ledgersPath(ledgersPath).zkc(zkc).build(); - allocationExecutor = Executors.newSingleThreadScheduledExecutor(); - } - - @After - public void teardown() throws Exception { - bkc.close(); - zkc.close(); - allocationExecutor.shutdown(); - } - - private ZKTransaction newTxn() { - return new ZKTransaction(zkc); - } - - private void validatePoolSize(LedgerAllocatorPool pool, - int pendingSize, - int allocatingSize, - int obtainingSize, - int rescueSize) { - assertEquals(pendingSize, pool.pendingListSize()); - assertEquals(allocatingSize, pool.allocatingListSize()); - assertEquals(obtainingSize, pool.obtainMapSize()); - assertEquals(rescueSize, pool.rescueSize()); - } - - @Test(timeout = 60000) - public void testNonAvailableAllocator() throws Exception { - String allocationPath = "/nonAvailableAllocator"; - - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(dlConf); - confLocal.setEnsembleSize(2 * numBookies); - confLocal.setWriteQuorumSize(2 * numBookies); - - int numAllocators = 3; - LedgerAllocatorPool pool = - new LedgerAllocatorPool(allocationPath, numAllocators, confLocal, zkc, bkc, allocationExecutor); - for (int i = 0; i < numAllocators; i++) { - try { - pool.allocate(); - Utils.ioResult(pool.tryObtain(newTxn(), NULL_LISTENER)); - fail("Should fail to allocate ledger if there are enought bookies"); - } catch (SimpleLedgerAllocator.AllocationException ae) { - assertEquals(SimpleLedgerAllocator.Phase.ERROR, ae.getPhase()); - } - } - for (int i = 0; i < numAllocators; i++) { - try { - pool.allocate(); - Utils.ioResult(pool.tryObtain(newTxn(), NULL_LISTENER)); - fail("Should fail to allocate ledger if there aren't available allocators"); - } catch (SimpleLedgerAllocator.AllocationException ae) { - assertEquals(SimpleLedgerAllocator.Phase.ERROR, ae.getPhase()); - } catch (IOException ioe) { - // expected - } - } - Utils.close(pool); - } - - @Test(timeout = 60000) - public void testRescueAllocators() throws Exception { - String allocationPath = "/rescueAllocators"; - - int numAllocators = 3; - LedgerAllocatorPool pool = - new LedgerAllocatorPool(allocationPath, numAllocators, dlConf, zkc, bkc, allocationExecutor); - List pendingTxns = Lists.newArrayListWithExpectedSize(numAllocators); - List allocatePaths = Lists.newArrayListWithExpectedSize(numAllocators); - for (int i = 0; i < numAllocators; i++) { - ZKTransaction txn = newTxn(); - pool.allocate(); - LedgerHandle lh = Utils.ioResult(pool.tryObtain(txn, NULL_LISTENER)); - - // get the corresponding ledger allocator - SimpleLedgerAllocator sla = pool.getLedgerAllocator(lh); - String slaPath = sla.allocatePath; - - logger.info("Allocated ledger {} from path {}", lh.getId(), slaPath); - - pendingTxns.add(txn); - allocatePaths.add(slaPath); - } - - for (int i = 0; i < numAllocators; i++) { - ZKTransaction txn = pendingTxns.get(i); - String slaPath = allocatePaths.get(i); - - // execute the transaction to confirm/abort obtain - Utils.ioResult(txn.execute()); - - // introduce error to individual ledger allocator - byte[] data = zkc.get().getData(slaPath, false, new Stat()); - zkc.get().setData(slaPath, data, -1); - } - int numSuccess = 0; - Set allocatedPathSet = new HashSet(); - while (numSuccess < 2 * numAllocators) { - try { - pool.allocate(); - ZKTransaction txn = newTxn(); - LedgerHandle lh = Utils.ioResult(pool.tryObtain(txn, NULL_LISTENER)); - - // get the corresponding ledger allocator - SimpleLedgerAllocator sla = pool.getLedgerAllocator(lh); - String slaPath = sla.allocatePath; - - logger.info("Allocated ledger {} from path {}", lh.getId(), slaPath); - allocatedPathSet.add(slaPath); - - Utils.ioResult(txn.execute()); - ++numSuccess; - } catch (IOException ioe) { - // continue - } - } - assertEquals(2 * numAllocators, numSuccess); - assertEquals(numAllocators, allocatedPathSet.size()); - Utils.close(pool); - } - - @Test(timeout = 60000) - public void testAllocateWhenNoAllocator() throws Exception { - String allocationPath = "/allocateWhenNoAllocator"; - LedgerAllocatorPool pool = new LedgerAllocatorPool(allocationPath, 0, dlConf, zkc, bkc, allocationExecutor); - try { - pool.allocate(); - fail("Should fail to allocate ledger if there isn't allocator."); - } catch (SimpleLedgerAllocator.AllocationException ae) { - fail("Should fail to allocate ledger if there isn't allocator."); - } catch (IOException ioe) { - // expected - } - Utils.close(pool); - } - - @Test(timeout = 60000) - public void testObtainWhenNoAllocator() throws Exception { - String allocationPath = "/obtainWhenNoAllocator"; - LedgerAllocatorPool pool = new LedgerAllocatorPool(allocationPath, 0, dlConf, zkc, bkc, allocationExecutor); - ZKTransaction txn = newTxn(); - try { - Utils.ioResult(pool.tryObtain(txn, NULL_LISTENER)); - fail("Should fail obtain ledger handle if there is no allocator."); - } catch (SimpleLedgerAllocator.AllocationException ae) { - fail("Should fail obtain ledger handle if there is no allocator."); - } catch (IOException ioe) { - // expected. - } - - Utils.close(pool); - } - - @Test(timeout = 60000) - public void testAllocateMultipleLedgers() throws Exception { - String allocationPath = "/" + runtime.getMethodName(); - int numAllocators = 5; - final LedgerAllocatorPool pool = - new LedgerAllocatorPool(allocationPath, numAllocators, dlConf, zkc, bkc, allocationExecutor); - int numLedgers = 20; - Set allocatedLedgers = new HashSet(); - for (int i = 0; i < numLedgers; i++) { - pool.allocate(); - ZKTransaction txn = newTxn(); - LedgerHandle lh = Utils.ioResult(pool.tryObtain(txn, NULL_LISTENER)); - Utils.ioResult(txn.execute()); - allocatedLedgers.add(lh); - } - assertEquals(numLedgers, allocatedLedgers.size()); - } - - @Test(timeout = 60000) - public void testConcurrentAllocation() throws Exception { - final int numAllocators = 5; - String allocationPath = "/concurrentAllocation"; - final LedgerAllocatorPool pool = - new LedgerAllocatorPool(allocationPath, numAllocators, dlConf, zkc, bkc, allocationExecutor); - final ConcurrentMap allocatedLedgers = - new ConcurrentHashMap(); - final AtomicInteger numFailures = new AtomicInteger(0); - Thread[] allocationThreads = new Thread[numAllocators]; - for (int i = 0; i < numAllocators; i++) { - final int tid = i; - allocationThreads[i] = new Thread() { - - int numLedgers = 50; - - @Override - public void run() { - try { - for (int i = 0; i < numLedgers; i++) { - pool.allocate(); - ZKTransaction txn = newTxn(); - LedgerHandle lh = Utils.ioResult(pool.tryObtain(txn, NULL_LISTENER)); - Utils.ioResult(txn.execute()); - lh.close(); - allocatedLedgers.putIfAbsent(lh.getId(), lh); - logger.info("[thread {}] allocate {}th ledger {}", tid, i, lh.getId()); - } - } catch (Exception ioe) { - numFailures.incrementAndGet(); - } - } - }; - } - - for (Thread t : allocationThreads) { - t.start(); - } - - for (Thread t : allocationThreads) { - t.join(); - } - - assertEquals(0, numFailures.get()); - assertEquals(50 * numAllocators, allocatedLedgers.size()); - - Utils.close(pool); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/PropertiesWriter.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/PropertiesWriter.java deleted file mode 100644 index f49d0cc3794..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/PropertiesWriter.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.config; - -import java.io.File; -import java.io.FileOutputStream; -import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer to write properties to files. - */ -public class PropertiesWriter { - static final Logger LOG = LoggerFactory.getLogger(PropertiesWriter.class); - - final FileOutputStream outputStream; - final File configFile; - final Properties properties; - - public PropertiesWriter() throws Exception { - this(null); - } - - public PropertiesWriter(File configFile) throws Exception { - if (null == configFile) { - this.configFile = File.createTempFile("temp", ".conf"); - } else { - this.configFile = configFile; - } - this.configFile.deleteOnExit(); - this.properties = new Properties(); - this.outputStream = new FileOutputStream(this.configFile); - } - - public void setProperty(String key, String value) { - properties.setProperty(key, value); - } - - public void removeProperty(String key) { - properties.remove(key); - } - - public void save() throws Exception { - FileOutputStream outputStream = new FileOutputStream(configFile); - properties.store(outputStream, null); - configFile.setLastModified(configFile.lastModified() + 1000); - if (LOG.isDebugEnabled()) { - LOG.debug("save modified={}", configFile.lastModified()); - } - } - - public File getFile() { - return configFile; - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicConfigurationFactory.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicConfigurationFactory.java deleted file mode 100644 index d8bac3cd49f..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicConfigurationFactory.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.config; - -import static org.junit.Assert.assertEquals; - -import com.google.common.base.Objects; -import java.io.File; -import java.util.Optional; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.common.config.ConcurrentBaseConfiguration; -import org.apache.distributedlog.common.config.ConcurrentConstConfiguration; -import org.apache.distributedlog.common.config.PropertiesWriter; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * TestDynamicConfigurationFactory. - */ -public class TestDynamicConfigurationFactory { - static final Logger LOG = LoggerFactory.getLogger(TestDynamicConfigurationFactory.class); - - private void waitForConfig(DynamicDistributedLogConfiguration conf, int value) throws Exception { - while (!Objects.equal(conf.getRetentionPeriodHours(), value)) { - Thread.sleep(100); - } - } - - private DynamicConfigurationFactory getConfigFactory(File configFile) { - String streamConfigPath = configFile.getParent(); - ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1); - ConcurrentBaseConfiguration defaultConf = new ConcurrentConstConfiguration(new DistributedLogConfiguration()); - return new DynamicConfigurationFactory(executorService, 100, TimeUnit.MILLISECONDS); - } - - private String getNamePart(File configFile) { - String propsFilename = configFile.getName(); - return propsFilename.substring(0, propsFilename.indexOf(".conf")); - } - - @Test(timeout = 60000) - public void testGetDynamicConfigBasics() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - DynamicConfigurationFactory factory = getConfigFactory(writer.getFile()); - Optional conf = factory.getDynamicConfiguration(writer.getFile().getPath()); - assertEquals(DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT, - conf.get().getRetentionPeriodHours()); - writer.setProperty(DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS, "1"); - writer.save(); - waitForConfig(conf.get(), 1); - assertEquals(1, conf.get().getRetentionPeriodHours()); - } - - @Test(timeout = 60000) - public void testGetDynamicConfigIsSingleton() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - DynamicConfigurationFactory factory = getConfigFactory(writer.getFile()); - String configPath = writer.getFile().getPath(); - Optional conf1 = factory.getDynamicConfiguration(configPath); - Optional conf2 = factory.getDynamicConfiguration(configPath); - assertEquals(conf1, conf2); - } - - /** - * If the file is missing, get-config should not fail, and the file should be picked up if its added. - * If the file is removed externally same should apply. - */ - @Test(timeout = 60000) - public void testMissingConfig() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - DynamicConfigurationFactory factory = getConfigFactory(writer.getFile()); - Optional conf = factory.getDynamicConfiguration(writer.getFile().getPath()); - writer.setProperty(DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS, "1"); - writer.save(); - waitForConfig(conf.get(), 1); - File configFile = writer.getFile(); - configFile.delete(); - Thread.sleep(1000); - PropertiesWriter writer2 = new PropertiesWriter(writer.getFile()); - writer2.setProperty(DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS, "2"); - writer2.save(); - waitForConfig(conf.get(), 2); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicDistributedLogConfiguration.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicDistributedLogConfiguration.java deleted file mode 100644 index 00d4a96f253..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/config/TestDynamicDistributedLogConfiguration.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.config; - - -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_ACK_QUORUM_SIZE; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_OLD; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_ENSEMBLE_SIZE; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_ENSEMBLE_SIZE_OLD; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_OLD; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_IS_DURABLE_WRITE_ENABLED; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_OUTPUT_BUFFER_SIZE; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_OUTPUT_BUFFER_SIZE_DEFAULT; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_OUTPUT_BUFFER_SIZE_OLD; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_READAHEAD_BATCHSIZE; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_READAHEAD_BATCHSIZE_DEFAULT; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_READAHEAD_BATCHSIZE_OLD; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_READAHEAD_MAX_RECORDS; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_READAHEAD_MAX_RECORDS_DEFAULT; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_READAHEAD_MAX_RECORDS_OLD; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT; -import static org.apache.distributedlog.DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS_OLD; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.bk.QuorumConfig; -import org.apache.distributedlog.common.config.ConcurrentBaseConfiguration; -import org.apache.distributedlog.common.config.ConcurrentConstConfiguration; -import org.junit.Test; - - -/** - * TestDynamicDistributedLogConfiguration. - */ -public class TestDynamicDistributedLogConfiguration { - - @Test(timeout = 20000) - public void testDefaults() throws Exception { - // Default config defines retention period plus two other params, but eaves ack quorum unspecified - DistributedLogConfiguration underlyingConfig = new DistributedLogConfiguration(); - underlyingConfig.setRetentionPeriodHours(99); - underlyingConfig.setProperty("rpsHardWriteLimit", 99); - - ConcurrentConstConfiguration defaultConfig = new ConcurrentConstConfiguration(underlyingConfig); - DynamicDistributedLogConfiguration config = new DynamicDistributedLogConfiguration(defaultConfig); - assertEquals(99, config.getRetentionPeriodHours()); - assertEquals(99, config.getRpsHardWriteLimit()); - config.setProperty(DistributedLogConfiguration.BKDL_RETENTION_PERIOD_IN_HOURS, 5); - - // Config checks primary then secondary then const defaults - assertEquals(5, config.getRetentionPeriodHours()); - assertEquals(99, config.getRpsHardWriteLimit()); - } - - @Test(timeout = 20000) - public void testGetRetentionPeriodHours() { - ConcurrentBaseConfiguration defaultConfig = new ConcurrentBaseConfiguration(); - DynamicDistributedLogConfiguration dynConf = new DynamicDistributedLogConfiguration(defaultConfig); - // get default value - assertEquals(BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT, dynConf.getRetentionPeriodHours()); - // get value from old key of default config - defaultConfig.setProperty(BKDL_RETENTION_PERIOD_IN_HOURS_OLD, BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 1); - assertEquals(BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 1, dynConf.getRetentionPeriodHours()); - // get value from new key of default config - defaultConfig.setProperty(BKDL_RETENTION_PERIOD_IN_HOURS, BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 2); - assertEquals(BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 2, dynConf.getRetentionPeriodHours()); - // get value from old key of dynamic config - dynConf.setProperty(BKDL_RETENTION_PERIOD_IN_HOURS_OLD, BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 3); - assertEquals(BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 3, dynConf.getRetentionPeriodHours()); - // get value from new key of default config - dynConf.setProperty(BKDL_RETENTION_PERIOD_IN_HOURS, BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 4); - assertEquals(BKDL_RETENTION_PERIOD_IN_HOURS_DEFAULT + 4, dynConf.getRetentionPeriodHours()); - } - - @Test(timeout = 20000) - public void testGetOutputBufferSize() { - ConcurrentBaseConfiguration defaultConfig = new ConcurrentBaseConfiguration(); - DynamicDistributedLogConfiguration dynConf = new DynamicDistributedLogConfiguration(defaultConfig); - // get default value - assertEquals(BKDL_OUTPUT_BUFFER_SIZE_DEFAULT, dynConf.getOutputBufferSize()); - // get value from old key of default config - defaultConfig.setProperty(BKDL_OUTPUT_BUFFER_SIZE_OLD, BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 1); - assertEquals(BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 1, dynConf.getOutputBufferSize()); - // get value from new key of default config - defaultConfig.setProperty(BKDL_OUTPUT_BUFFER_SIZE, BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 2); - assertEquals(BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 2, dynConf.getOutputBufferSize()); - // get value from old key of dynamic config - dynConf.setProperty(BKDL_OUTPUT_BUFFER_SIZE_OLD, BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 3); - assertEquals(BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 3, dynConf.getOutputBufferSize()); - // get value from new key of default config - dynConf.setProperty(BKDL_OUTPUT_BUFFER_SIZE, BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 4); - assertEquals(BKDL_OUTPUT_BUFFER_SIZE_DEFAULT + 4, dynConf.getOutputBufferSize()); - } - - @Test(timeout = 20000) - public void testGetReadAheadBatchSize() { - ConcurrentBaseConfiguration defaultConfig = new ConcurrentBaseConfiguration(); - DynamicDistributedLogConfiguration dynConf = new DynamicDistributedLogConfiguration(defaultConfig); - // get default value - assertEquals(BKDL_READAHEAD_BATCHSIZE_DEFAULT, dynConf.getReadAheadBatchSize()); - // get value from old key of default config - defaultConfig.setProperty(BKDL_READAHEAD_BATCHSIZE_OLD, BKDL_READAHEAD_BATCHSIZE_DEFAULT + 1); - assertEquals(BKDL_READAHEAD_BATCHSIZE_DEFAULT + 1, dynConf.getReadAheadBatchSize()); - // get value from new key of default config - defaultConfig.setProperty(BKDL_READAHEAD_BATCHSIZE, BKDL_READAHEAD_BATCHSIZE_DEFAULT + 2); - assertEquals(BKDL_READAHEAD_BATCHSIZE_DEFAULT + 2, dynConf.getReadAheadBatchSize()); - // get value from old key of dynamic config - dynConf.setProperty(BKDL_READAHEAD_BATCHSIZE_OLD, BKDL_READAHEAD_BATCHSIZE_DEFAULT + 3); - assertEquals(BKDL_READAHEAD_BATCHSIZE_DEFAULT + 3, dynConf.getReadAheadBatchSize()); - // get value from new key of default config - dynConf.setProperty(BKDL_READAHEAD_BATCHSIZE, BKDL_READAHEAD_BATCHSIZE_DEFAULT + 4); - assertEquals(BKDL_READAHEAD_BATCHSIZE_DEFAULT + 4, dynConf.getReadAheadBatchSize()); - } - - @Test(timeout = 20000) - public void testGetReadAheadMaxRecords() { - ConcurrentBaseConfiguration defaultConfig = new ConcurrentBaseConfiguration(); - DynamicDistributedLogConfiguration dynConf = new DynamicDistributedLogConfiguration(defaultConfig); - // get default value - assertEquals(BKDL_READAHEAD_MAX_RECORDS_DEFAULT, dynConf.getReadAheadMaxRecords()); - // get value from old key of default config - defaultConfig.setProperty(BKDL_READAHEAD_MAX_RECORDS_OLD, BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 1); - assertEquals(BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 1, dynConf.getReadAheadMaxRecords()); - // get value from new key of default config - defaultConfig.setProperty(BKDL_READAHEAD_MAX_RECORDS, BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 2); - assertEquals(BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 2, dynConf.getReadAheadMaxRecords()); - // get value from old key of dynamic config - dynConf.setProperty(BKDL_READAHEAD_MAX_RECORDS_OLD, BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 3); - assertEquals(BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 3, dynConf.getReadAheadMaxRecords()); - // get value from new key of default config - dynConf.setProperty(BKDL_READAHEAD_MAX_RECORDS, BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 4); - assertEquals(BKDL_READAHEAD_MAX_RECORDS_DEFAULT + 4, dynConf.getReadAheadMaxRecords()); - } - - void assertQuorumConfig(QuorumConfig config, - int expectedEnsembleSize, - int expectedWriteQuorumSize, - int expectedAckQuorumSize) { - assertEquals(expectedEnsembleSize, config.getEnsembleSize()); - assertEquals(expectedWriteQuorumSize, config.getWriteQuorumSize()); - assertEquals(expectedAckQuorumSize, config.getAckQuorumSize()); - } - - @Test(timeout = 20000) - public void testGetQuorumConfig() { - ConcurrentBaseConfiguration defaultConfig = new ConcurrentBaseConfiguration(); - DynamicDistributedLogConfiguration dynConf = new DynamicDistributedLogConfiguration(defaultConfig); - // get default value - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - - // Test Ensemble Size - - // get value from old key of default config - defaultConfig.setProperty(BKDL_BOOKKEEPER_ENSEMBLE_SIZE_OLD, BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 1); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 1, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - // get value from new key of default config - defaultConfig.setProperty(BKDL_BOOKKEEPER_ENSEMBLE_SIZE, BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 2); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 2, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - // get value from old key of dynamic config - dynConf.setProperty(BKDL_BOOKKEEPER_ENSEMBLE_SIZE_OLD, BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 3); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 3, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - // get value from new key of dynamic config - dynConf.setProperty(BKDL_BOOKKEEPER_ENSEMBLE_SIZE, BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - - // Test Write Quorum Size - - // get value from old key of default config - defaultConfig.setProperty(BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_OLD, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 1); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 1, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - // get value from new key of default config - defaultConfig.setProperty(BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 2); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 2, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - // get value from old key of dynamic config - dynConf.setProperty(BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_OLD, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 3); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 3, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - // get value from new key of dynamic config - dynConf.setProperty(BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 4); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT); - - // Test Ack Quorum Size - - // get value from old key of default config - defaultConfig.setProperty(BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_OLD, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 1); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 1); - // get value from new key of default config - defaultConfig.setProperty(BKDL_BOOKKEEPER_ACK_QUORUM_SIZE, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 2); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 2); - // get value from old key of dynamic config - dynConf.setProperty(BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_OLD, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 3); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 3); - // get value from new key of dynamic config - dynConf.setProperty(BKDL_BOOKKEEPER_ACK_QUORUM_SIZE, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 4); - assertQuorumConfig( - dynConf.getQuorumConfig(), - BKDL_BOOKKEEPER_ENSEMBLE_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_WRITE_QUORUM_SIZE_DEFAULT + 4, - BKDL_BOOKKEEPER_ACK_QUORUM_SIZE_DEFAULT + 4); - } - - @Test(timeout = 20000) - public void testIsDurableWriteEnabled() { - ConcurrentBaseConfiguration defaultConfig = new ConcurrentBaseConfiguration(); - DynamicDistributedLogConfiguration dynConf = new DynamicDistributedLogConfiguration(defaultConfig); - - assertTrue(dynConf.isDurableWriteEnabled()); - defaultConfig.setProperty(BKDL_IS_DURABLE_WRITE_ENABLED, false); - assertFalse(dynConf.isDurableWriteEnabled()); - dynConf.setProperty(BKDL_IS_DURABLE_WRITE_ENABLED, true); - assertTrue(dynConf.isDurableWriteEnabled()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestConfigurationFeatureProvider.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestConfigurationFeatureProvider.java deleted file mode 100644 index a35a5117c1c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestConfigurationFeatureProvider.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.feature; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import org.apache.bookkeeper.feature.Feature; -import org.apache.bookkeeper.feature.SettableFeature; -import org.apache.distributedlog.common.config.ConcurrentBaseConfiguration; -import org.junit.Test; - - - -/** - * Test case for configuration based feature provider. - */ -public class TestConfigurationFeatureProvider { - - @Test(timeout = 60000) - public void testConfigurationFeatureProvider() throws Exception { - String rootScope = "dl"; - ConcurrentBaseConfiguration featureConf = - new ConcurrentBaseConfiguration(); - ConcurrentMap features = - new ConcurrentHashMap(); - ConfigurationFeatureProvider featureProvider = - new ConfigurationFeatureProvider(rootScope, featureConf, features); - - String featureName1 = "feature1"; - String fullFeatureName1 = rootScope + "." + featureName1; - int availability1 = 1234; - featureConf.setProperty(fullFeatureName1, availability1); - Feature feature1 = featureProvider.getFeature(featureName1); - assertEquals(availability1, feature1.availability()); - assertTrue(features.containsKey(fullFeatureName1)); - assertTrue(feature1 == features.get(fullFeatureName1)); - - String subScope = "subscope"; - String featureName2 = "feature2"; - String fullFeatureName2 = rootScope + "." + subScope + "." + featureName2; - int availability2 = 4321; - featureConf.setProperty(fullFeatureName2, availability2); - Feature feature2 = featureProvider.scope(subScope).getFeature(featureName2); - assertEquals(availability2, feature2.availability()); - assertTrue(features.containsKey(fullFeatureName2)); - assertTrue(feature2 == features.get(fullFeatureName2)); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java deleted file mode 100644 index 1ebab1e5457..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.feature; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.feature.Feature; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.common.config.PropertiesWriter; -import org.junit.Test; - -/** - * Test case for dynamic configuration based feature provider. - */ -public class TestDynamicConfigurationFeatureProvider { - - /** - * Make sure config is reloaded. - *Give FileChangedReloadingStrategy some time to allow reloading - * Make sure now!=lastChecked - * {@link org.apache.commons.configuration.reloading.FileChangedReloadingStrategy#reloadingRequired()} - */ - private void ensureConfigReloaded() throws InterruptedException { - // sleep 1 ms so that System.currentTimeMillis() != - // lastChecked (the time we construct FileChangedReloadingStrategy - Thread.sleep(1); - } - - @Test(timeout = 60000) - public void testLoadFeaturesFromBase() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - writer.setProperty("feature_1", "10000"); - writer.setProperty("feature_2", "5000"); - writer.save(); - - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setDynamicConfigReloadIntervalSec(Integer.MAX_VALUE) - .setFileFeatureProviderBaseConfigPath(writer.getFile().toURI().toURL().getPath()); - DynamicConfigurationFeatureProvider provider = - new DynamicConfigurationFeatureProvider("", conf, NullStatsLogger.INSTANCE); - provider.start(); - ensureConfigReloaded(); - - Feature feature1 = provider.getFeature("feature_1"); - assertTrue(feature1.isAvailable()); - assertEquals(10000, feature1.availability()); - Feature feature2 = provider.getFeature("feature_2"); - assertTrue(feature2.isAvailable()); - assertEquals(5000, feature2.availability()); - Feature feature3 = provider.getFeature("feature_3"); - assertFalse(feature3.isAvailable()); - assertEquals(0, feature3.availability()); - Feature feature4 = provider.getFeature("unknown_feature"); - assertFalse(feature4.isAvailable()); - assertEquals(0, feature4.availability()); - - provider.stop(); - } - - @FlakyTest("https://issues.apache.org/jira/browse/DL-40") - public void testLoadFeaturesFromOverlay() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - writer.setProperty("feature_1", "10000"); - writer.setProperty("feature_2", "5000"); - writer.save(); - - PropertiesWriter overlayWriter = new PropertiesWriter(); - overlayWriter.setProperty("feature_2", "6000"); - overlayWriter.setProperty("feature_4", "6000"); - overlayWriter.save(); - - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setDynamicConfigReloadIntervalSec(Integer.MAX_VALUE) - .setFileFeatureProviderBaseConfigPath(writer.getFile().toURI().toURL().getPath()) - .setFileFeatureProviderOverlayConfigPath(overlayWriter.getFile().toURI().toURL().getPath()); - DynamicConfigurationFeatureProvider provider = - new DynamicConfigurationFeatureProvider("", conf, NullStatsLogger.INSTANCE); - provider.start(); - ensureConfigReloaded(); - - Feature feature1 = provider.getFeature("feature_1"); - assertTrue(feature1.isAvailable()); - assertEquals(10000, feature1.availability()); - Feature feature2 = provider.getFeature("feature_2"); - assertTrue(feature2.isAvailable()); - assertEquals(6000, feature2.availability()); - Feature feature3 = provider.getFeature("feature_3"); - assertFalse(feature3.isAvailable()); - assertEquals(0, feature3.availability()); - Feature feature4 = provider.getFeature("feature_4"); - assertTrue(feature4.isAvailable()); - assertEquals(6000, feature4.availability()); - Feature feature5 = provider.getFeature("unknown_feature"); - assertFalse(feature5.isAvailable()); - assertEquals(0, feature5.availability()); - - provider.stop(); - } - - @Test(timeout = 60000) - public void testReloadFeaturesFromOverlay() throws Exception { - PropertiesWriter writer = new PropertiesWriter(); - writer.setProperty("feature_1", "10000"); - writer.setProperty("feature_2", "5000"); - writer.save(); - - PropertiesWriter overlayWriter = new PropertiesWriter(); - overlayWriter.setProperty("feature_2", "6000"); - overlayWriter.setProperty("feature_4", "6000"); - overlayWriter.save(); - - DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setDynamicConfigReloadIntervalSec(Integer.MAX_VALUE) - .setFileFeatureProviderBaseConfigPath(writer.getFile().toURI().toURL().getPath()) - .setFileFeatureProviderOverlayConfigPath(overlayWriter.getFile().toURI().toURL().getPath()); - DynamicConfigurationFeatureProvider provider = - new DynamicConfigurationFeatureProvider("", conf, NullStatsLogger.INSTANCE); - provider.start(); - ensureConfigReloaded(); - - Feature feature1 = provider.getFeature("feature_1"); - assertTrue(feature1.isAvailable()); - assertEquals(10000, feature1.availability()); - Feature feature2 = provider.getFeature("feature_2"); - assertTrue(feature2.isAvailable()); - assertEquals(6000, feature2.availability()); - Feature feature3 = provider.getFeature("feature_3"); - assertFalse(feature3.isAvailable()); - assertEquals(0, feature3.availability()); - Feature feature4 = provider.getFeature("feature_4"); - assertTrue(feature4.isAvailable()); - assertEquals(6000, feature4.availability()); - Feature feature5 = provider.getFeature("unknown_feature"); - assertFalse(feature5.isAvailable()); - assertEquals(0, feature5.availability()); - - // dynamic load config - provider.getFeatureConf().setProperty("feature_1", 3000); - provider.getFeatureConf().setProperty("feature_2", 7000); - provider.getFeatureConf().setProperty("feature_3", 8000); - provider.getFeatureConf().setProperty("feature_4", 9000); - provider.onReload(provider.getFeatureConf()); - feature1 = provider.getFeature("feature_1"); - assertTrue(feature1.isAvailable()); - assertEquals(3000, feature1.availability()); - feature2 = provider.getFeature("feature_2"); - assertTrue(feature2.isAvailable()); - assertEquals(7000, feature2.availability()); - feature3 = provider.getFeature("feature_3"); - assertTrue(feature3.isAvailable()); - assertEquals(8000, feature3.availability()); - feature4 = provider.getFeature("feature_4"); - assertTrue(feature4.isAvailable()); - assertEquals(9000, feature4.availability()); - - provider.stop(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogMetadataStore.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogMetadataStore.java deleted file mode 100644 index 1a4ef238b1d..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogMetadataStore.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Sets; -import java.net.URI; -import java.util.Optional; -import java.util.Set; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Test ZK based metadata store. - */ -public class TestZKLogMetadataStore extends TestDistributedLogBase { - - private static final int zkSessionTimeoutMs = 2000; - - @Rule - public TestName runtime = new TestName(); - protected final DistributedLogConfiguration baseConf = - new DistributedLogConfiguration(); - protected ZooKeeperClient zkc; - protected ZKLogMetadataStore metadataStore; - protected OrderedScheduler scheduler; - protected URI uri; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createDLMURI("/")) - .sessionTimeoutMs(zkSessionTimeoutMs) - .build(); - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-zk-logmetadata-store") - .numThreads(1) - .build(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.addConfiguration(baseConf); - this.uri = createDLMURI("/" + runtime.getMethodName()); - metadataStore = new ZKLogMetadataStore(conf, uri, zkc, scheduler); - } - - @After - public void teardown() throws Exception { - if (null != zkc) { - zkc.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - } - - private void createLogInNamespace(URI uri, String logName) throws Exception { - String logPath = uri.getPath() + "/" + logName; - Utils.zkCreateFullPathOptimistic(zkc, logPath, new byte[0], - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } - - @Test(timeout = 60000) - public void testCreateLog() throws Exception { - assertEquals(uri, Utils.ioResult(metadataStore.createLog("test"))); - } - - @Test(timeout = 60000) - public void testGetLogLocation() throws Exception { - Optional uriOptional = Utils.ioResult(metadataStore.getLogLocation("test")); - assertTrue(uriOptional.isPresent()); - assertEquals(uri, uriOptional.get()); - } - - @Test(timeout = 60000) - public void testGetLogs() throws Exception { - Set logs = Sets.newHashSet(); - for (int i = 0; i < 10; i++) { - String logName = "test-" + i; - logs.add(logName); - createLogInNamespace(uri, logName); - } - Set result = Sets.newHashSet(Utils.ioResult(metadataStore.getLogs(""))); - assertEquals(10, result.size()); - assertTrue(Sets.difference(logs, result).isEmpty()); - } - - @Test(timeout = 60000) - public void testGetLogsPrefix() throws Exception { - Set logs = Sets.newHashSet(); - for (int i = 0; i < 10; i++) { - String logName = "test-" + i; - logs.add(logName); - createLogInNamespace(uri, "test/" + logName); - } - Set result = Sets.newHashSet(Utils.ioResult(metadataStore.getLogs("test"))); - assertEquals(10, result.size()); - assertTrue(Sets.difference(logs, result).isEmpty()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentFilters.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentFilters.java deleted file mode 100644 index cefee7d783d..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentFilters.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl; - -import static org.apache.distributedlog.impl.ZKLogSegmentFilters.WRITE_HANDLE_FILTER; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DistributedLogConstants; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - - - -/** - * TestZKLogSegmentFilters. - */ -public class TestZKLogSegmentFilters { - - static final Logger LOG = LoggerFactory.getLogger(TestZKLogSegmentFilters.class); - - @Test(timeout = 60000) - public void testWriteFilter() { - Set expectedFilteredSegments = new HashSet(); - List segments = new ArrayList(); - for (int i = 1; i <= 5; i++) { - segments.add(DLMTestUtil.completedLedgerZNodeNameWithVersion(i, (i - 1) * 100, i * 100 - 1, i)); - } - for (int i = 6; i <= 10; i++) { - String segmentName = DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i); - segments.add(segmentName); - if (i == 10) { - expectedFilteredSegments.add(segmentName); - } - } - for (int i = 11; i <= 15; i++) { - String segmentName = DLMTestUtil.completedLedgerZNodeNameWithTxID((i - 1) * 100, i * 100 - 1); - segments.add(segmentName); - expectedFilteredSegments.add(segmentName); - } - segments.add(""); - segments.add("unknown"); - segments.add(DistributedLogConstants.COMPLETED_LOGSEGMENT_PREFIX + "_1234_5678_9"); - expectedFilteredSegments.add(DistributedLogConstants.COMPLETED_LOGSEGMENT_PREFIX + "_1234_5678_9"); - segments.add(DistributedLogConstants.COMPLETED_LOGSEGMENT_PREFIX + "_1_2_3_4_5_6_7_8_9"); - expectedFilteredSegments.add(DistributedLogConstants.COMPLETED_LOGSEGMENT_PREFIX + "_1_2_3_4_5_6_7_8_9"); - - Collection filteredCollection = WRITE_HANDLE_FILTER.filter(segments); - LOG.info("Filter log segments {} to {}.", segments, filteredCollection); - assertEquals(expectedFilteredSegments.size(), filteredCollection.size()); - - Set filteredSegments = Sets.newHashSet(filteredCollection); - Sets.SetView diff = Sets.difference(filteredSegments, expectedFilteredSegments); - assertTrue(diff.isEmpty()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentMetadataStore.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentMetadataStore.java deleted file mode 100644 index f466a781d30..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKLogSegmentMetadataStore.java +++ /dev/null @@ -1,834 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import java.net.URI; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.LogSegmentMetadata; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClientUtils; -import org.apache.distributedlog.callback.LogSegmentNamesListener; -import org.apache.distributedlog.exceptions.ZKException; -import org.apache.distributedlog.metadata.LogMetadata; -import org.apache.distributedlog.metadata.LogMetadataForWriter; -import org.apache.distributedlog.util.DLUtils; -import org.apache.distributedlog.util.Transaction; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test ZK based log segment metadata store. - */ -public class TestZKLogSegmentMetadataStore extends TestDistributedLogBase { - - private static final Logger logger = LoggerFactory.getLogger(TestZKLogSegmentMetadataStore.class); - - private static final int zkSessionTimeoutMs = 2000; - - private LogSegmentMetadata createLogSegment( - long logSegmentSequenceNumber) { - return createLogSegment(logSegmentSequenceNumber, 99L); - } - - private LogSegmentMetadata createLogSegment( - long logSegmentSequenceNumber, - long lastEntryId) { - return DLMTestUtil.completedLogSegment( - "/" + runtime.getMethodName(), - logSegmentSequenceNumber, - logSegmentSequenceNumber, - 1L, - 100, - logSegmentSequenceNumber, - lastEntryId, - 0L, - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - } - - @Rule - public TestName runtime = new TestName(); - protected final DistributedLogConfiguration baseConf = - new DistributedLogConfiguration(); - protected ZooKeeperClient zkc; - protected ZKLogSegmentMetadataStore lsmStore; - protected OrderedScheduler scheduler; - protected URI uri; - protected String rootZkPath; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createDLMURI("/")) - .sessionTimeoutMs(zkSessionTimeoutMs) - .build(); - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-zk-logsegment-metadata-store") - .numThreads(1) - .build(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.addConfiguration(baseConf); - this.uri = createDLMURI("/" + runtime.getMethodName()); - lsmStore = new ZKLogSegmentMetadataStore(conf, zkc, scheduler); - zkc.get().create( - "/" + runtime.getMethodName(), - new byte[0], - ZooDefs.Ids.OPEN_ACL_UNSAFE, - CreateMode.PERSISTENT); - this.rootZkPath = "/" + runtime.getMethodName(); - } - - @After - public void teardown() throws Exception { - if (null != zkc) { - zkc.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - } - - @Test(timeout = 60000) - public void testCreateLogSegment() throws Exception { - LogSegmentMetadata segment = createLogSegment(1L); - Transaction createTxn = lsmStore.transaction(); - lsmStore.createLogSegment(createTxn, segment, null); - Utils.ioResult(createTxn.execute()); - // the log segment should be created - assertNotNull("LogSegment " + segment + " should be created", - zkc.get().exists(segment.getZkPath(), false)); - LogSegmentMetadata segment2 = createLogSegment(1L); - Transaction createTxn2 = lsmStore.transaction(); - lsmStore.createLogSegment(createTxn2, segment2, null); - try { - Utils.ioResult(createTxn2.execute()); - fail("Should fail if log segment exists"); - } catch (Throwable t) { - // expected - assertTrue("Should throw NodeExistsException if log segment exists", - t instanceof ZKException); - ZKException zke = (ZKException) t; - assertEquals("Should throw NodeExistsException if log segment exists", - KeeperException.Code.NODEEXISTS, zke.getKeeperExceptionCode()); - } - } - - @Test(timeout = 60000) - public void testDeleteLogSegment() throws Exception { - LogSegmentMetadata segment = createLogSegment(1L); - Transaction createTxn = lsmStore.transaction(); - lsmStore.createLogSegment(createTxn, segment, null); - Utils.ioResult(createTxn.execute()); - // the log segment should be created - assertNotNull("LogSegment " + segment + " should be created", - zkc.get().exists(segment.getZkPath(), false)); - Transaction deleteTxn = lsmStore.transaction(); - lsmStore.deleteLogSegment(deleteTxn, segment, null); - Utils.ioResult(deleteTxn.execute()); - assertNull("LogSegment " + segment + " should be deleted", - zkc.get().exists(segment.getZkPath(), false)); - } - - @Test(timeout = 60000) - public void testDeleteNonExistentLogSegment() throws Exception { - LogSegmentMetadata segment = createLogSegment(1L); - Transaction deleteTxn = lsmStore.transaction(); - lsmStore.deleteLogSegment(deleteTxn, segment, null); - try { - Utils.ioResult(deleteTxn.execute()); - fail("Should fail deletion if log segment doesn't exist"); - } catch (Throwable t) { - assertTrue("Should throw NoNodeException if log segment doesn't exist", - t instanceof ZKException); - ZKException zke = (ZKException) t; - assertEquals("Should throw NoNodeException if log segment doesn't exist", - KeeperException.Code.NONODE, zke.getKeeperExceptionCode()); - } - } - - @Test(timeout = 60000) - public void testUpdateNonExistentLogSegment() throws Exception { - LogSegmentMetadata segment = createLogSegment(1L); - Transaction updateTxn = lsmStore.transaction(); - lsmStore.updateLogSegment(updateTxn, segment); - try { - Utils.ioResult(updateTxn.execute()); - fail("Should fail update if log segment doesn't exist"); - } catch (Throwable t) { - assertTrue("Should throw NoNodeException if log segment doesn't exist", - t instanceof ZKException); - ZKException zke = (ZKException) t; - assertEquals("Should throw NoNodeException if log segment doesn't exist", - KeeperException.Code.NONODE, zke.getKeeperExceptionCode()); - } - } - - @Test(timeout = 60000) - public void testUpdateLogSegment() throws Exception { - LogSegmentMetadata segment = createLogSegment(1L, 99L); - Transaction createTxn = lsmStore.transaction(); - lsmStore.createLogSegment(createTxn, segment, null); - Utils.ioResult(createTxn.execute()); - // the log segment should be created - assertNotNull("LogSegment " + segment + " should be created", - zkc.get().exists(segment.getZkPath(), false)); - LogSegmentMetadata modifiedSegment = createLogSegment(1L, 999L); - Transaction updateTxn = lsmStore.transaction(); - lsmStore.updateLogSegment(updateTxn, modifiedSegment); - Utils.ioResult(updateTxn.execute()); - // the log segment should be updated - LogSegmentMetadata readSegment = - Utils.ioResult(LogSegmentMetadata.read(zkc, segment.getZkPath(), true)); - assertEquals("Last entry id should be changed from 99L to 999L", - 999L, readSegment.getLastEntryId()); - } - - @Test(timeout = 60000) - public void testCreateDeleteLogSegmentSuccess() throws Exception { - LogSegmentMetadata segment1 = createLogSegment(1L); - LogSegmentMetadata segment2 = createLogSegment(2L); - // create log segment 1 - Transaction createTxn = lsmStore.transaction(); - lsmStore.createLogSegment(createTxn, segment1, null); - Utils.ioResult(createTxn.execute()); - // the log segment should be created - assertNotNull("LogSegment " + segment1 + " should be created", - zkc.get().exists(segment1.getZkPath(), false)); - // delete log segment 1 and create log segment 2 - Transaction createDeleteTxn = lsmStore.transaction(); - lsmStore.createLogSegment(createDeleteTxn, segment2, null); - lsmStore.deleteLogSegment(createDeleteTxn, segment1, null); - Utils.ioResult(createDeleteTxn.execute()); - // segment 1 should be deleted, segment 2 should be created - assertNull("LogSegment " + segment1 + " should be deleted", - zkc.get().exists(segment1.getZkPath(), false)); - assertNotNull("LogSegment " + segment2 + " should be created", - zkc.get().exists(segment2.getZkPath(), false)); - } - - @Test(timeout = 60000) - public void testCreateDeleteLogSegmentFailure() throws Exception { - LogSegmentMetadata segment1 = createLogSegment(1L); - LogSegmentMetadata segment2 = createLogSegment(2L); - LogSegmentMetadata segment3 = createLogSegment(3L); - // create log segment 1 - Transaction createTxn = lsmStore.transaction(); - lsmStore.createLogSegment(createTxn, segment1, null); - Utils.ioResult(createTxn.execute()); - // the log segment should be created - assertNotNull("LogSegment " + segment1 + " should be created", - zkc.get().exists(segment1.getZkPath(), false)); - // delete log segment 1 and delete log segment 2 - Transaction createDeleteTxn = lsmStore.transaction(); - lsmStore.deleteLogSegment(createDeleteTxn, segment1, null); - lsmStore.deleteLogSegment(createDeleteTxn, segment2, null); - lsmStore.createLogSegment(createDeleteTxn, segment3, null); - try { - Utils.ioResult(createDeleteTxn.execute()); - fail("Should fail transaction if one operation failed"); - } catch (Throwable t) { - assertTrue("Transaction is aborted", - t instanceof ZKException); - ZKException zke = (ZKException) t; - assertEquals("Transaction is aborted", - KeeperException.Code.NONODE, zke.getKeeperExceptionCode()); - } - // segment 1 should not be deleted - assertNotNull("LogSegment " + segment1 + " should not be deleted", - zkc.get().exists(segment1.getZkPath(), false)); - // segment 3 should not be created - assertNull("LogSegment " + segment3 + " should be created", - zkc.get().exists(segment3.getZkPath(), false)); - } - - @Test(timeout = 60000) - public void testGetLogSegment() throws Exception { - LogSegmentMetadata segment = createLogSegment(1L, 99L); - Transaction createTxn = lsmStore.transaction(); - lsmStore.createLogSegment(createTxn, segment, null); - Utils.ioResult(createTxn.execute()); - // the log segment should be created - assertNotNull("LogSegment " + segment + " should be created", - zkc.get().exists(segment.getZkPath(), false)); - LogSegmentMetadata readSegment = - Utils.ioResult(lsmStore.getLogSegment(segment.getZkPath())); - assertEquals("Log segment should match", - segment, readSegment); - } - - @Test(timeout = 60000) - public void testGetLogSegmentNames() throws Exception { - Transaction createTxn = lsmStore.transaction(); - List createdSegments = Lists.newArrayListWithExpectedSize(10); - for (int i = 0; i < 10; i++) { - LogSegmentMetadata segment = createLogSegment(i); - createdSegments.add(segment); - lsmStore.createLogSegment(createTxn, segment, null); - } - Utils.ioResult(createTxn.execute()); - String rootPath = "/" + runtime.getMethodName(); - List children = zkc.get().getChildren(rootPath, false); - Collections.sort(children); - assertEquals("Should find 10 log segments", - 10, children.size()); - List logSegmentNames = - Utils.ioResult(lsmStore.getLogSegmentNames(rootPath, null)).getValue(); - Collections.sort(logSegmentNames); - assertEquals("Should find 10 log segments", - 10, logSegmentNames.size()); - assertEquals(children, logSegmentNames); - List> getFutures = Lists.newArrayListWithExpectedSize(10); - for (int i = 0; i < 10; i++) { - getFutures.add(lsmStore.getLogSegment(rootPath + "/" + logSegmentNames.get(i))); - } - List segments = - Utils.ioResult(FutureUtils.collect(getFutures)); - for (int i = 0; i < 10; i++) { - assertEquals(createdSegments.get(i), segments.get(i)); - } - } - - @Test(timeout = 60000) - public void testRegisterListenerAfterLSMStoreClosed() throws Exception { - lsmStore.close(); - LogSegmentMetadata segment = createLogSegment(1L); - lsmStore.getLogSegmentNames(segment.getZkPath(), new LogSegmentNamesListener() { - @Override - public void onSegmentsUpdated(Versioned> segments) { - // no-op; - } - @Override - public void onLogStreamDeleted() { - // no-op; - } - }); - assertTrue("No listener is registered", - lsmStore.listeners.isEmpty()); - } - - @Test(timeout = 60000) - public void testLogSegmentNamesListener() throws Exception { - int numSegments = 3; - Transaction createTxn = lsmStore.transaction(); - for (int i = 0; i < numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.createLogSegment(createTxn, segment, null); - } - Utils.ioResult(createTxn.execute()); - String rootPath = "/" + runtime.getMethodName(); - List children = zkc.get().getChildren(rootPath, false); - Collections.sort(children); - - final AtomicInteger numNotifications = new AtomicInteger(0); - final List> segmentLists = Lists.newArrayListWithExpectedSize(2); - LogSegmentNamesListener listener = new LogSegmentNamesListener() { - @Override - public void onSegmentsUpdated(Versioned> segments) { - logger.info("Received segments : {}", segments); - segmentLists.add(segments.getValue()); - numNotifications.incrementAndGet(); - } - @Override - public void onLogStreamDeleted() { - // no-op; - } - }; - lsmStore.getLogSegmentNames(rootPath, listener); - assertEquals(1, lsmStore.listeners.size()); - assertTrue("Should contain listener", lsmStore.listeners.containsKey(rootPath)); - assertTrue("Should contain listener", lsmStore.listeners.get(rootPath).containsKey(listener)); - while (numNotifications.get() < 1) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive one segment list update", - 1, numNotifications.get()); - List firstSegmentList = segmentLists.get(0); - Collections.sort(firstSegmentList); - assertEquals("List of segments should be same", - children, firstSegmentList); - - logger.info("Create another {} segments.", numSegments); - - // create another log segment, it should trigger segment list updated - Transaction anotherCreateTxn = lsmStore.transaction(); - for (int i = numSegments; i < 2 * numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.createLogSegment(anotherCreateTxn, segment, null); - } - Utils.ioResult(anotherCreateTxn.execute()); - List newChildren = zkc.get().getChildren(rootPath, false); - Collections.sort(newChildren); - logger.info("All log segments become {}", newChildren); - while (numNotifications.get() < 2) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive second segment list update", - 2, numNotifications.get()); - List secondSegmentList = segmentLists.get(1); - Collections.sort(secondSegmentList); - assertEquals("List of segments should be updated", - 2 * numSegments, secondSegmentList.size()); - assertEquals("List of segments should be updated", - newChildren, secondSegmentList); - } - - @Test(timeout = 60000) - public void testLogSegmentNamesListenerOnDeletion() throws Exception { - int numSegments = 3; - Transaction createTxn = lsmStore.transaction(); - for (int i = 0; i < numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.createLogSegment(createTxn, segment, null); - } - Utils.ioResult(createTxn.execute()); - String rootPath = "/" + runtime.getMethodName(); - List children = zkc.get().getChildren(rootPath, false); - Collections.sort(children); - - final AtomicInteger numNotifications = new AtomicInteger(0); - final List> segmentLists = Lists.newArrayListWithExpectedSize(2); - LogSegmentNamesListener listener = new LogSegmentNamesListener() { - @Override - public void onSegmentsUpdated(Versioned> segments) { - logger.info("Received segments : {}", segments); - segmentLists.add(segments.getValue()); - numNotifications.incrementAndGet(); - } - - @Override - public void onLogStreamDeleted() { - // no-op; - } - }; - lsmStore.getLogSegmentNames(rootPath, listener); - assertEquals(1, lsmStore.listeners.size()); - assertTrue("Should contain listener", lsmStore.listeners.containsKey(rootPath)); - assertTrue("Should contain listener", lsmStore.listeners.get(rootPath).containsKey(listener)); - while (numNotifications.get() < 1) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive one segment list update", - 1, numNotifications.get()); - List firstSegmentList = segmentLists.get(0); - Collections.sort(firstSegmentList); - assertEquals("List of segments should be same", - children, firstSegmentList); - - // delete all log segments, it should trigger segment list updated - Transaction deleteTxn = lsmStore.transaction(); - for (int i = 0; i < numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.deleteLogSegment(deleteTxn, segment, null); - } - Utils.ioResult(deleteTxn.execute()); - List newChildren = zkc.get().getChildren(rootPath, false); - Collections.sort(newChildren); - while (numNotifications.get() < 2) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive second segment list update", - 2, numNotifications.get()); - List secondSegmentList = segmentLists.get(1); - Collections.sort(secondSegmentList); - assertEquals("List of segments should be updated", - 0, secondSegmentList.size()); - assertEquals("List of segments should be updated", - newChildren, secondSegmentList); - - // delete the root path - zkc.get().delete(rootPath, -1); - while (!lsmStore.listeners.isEmpty()) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertTrue("listener should be removed after root path is deleted", - lsmStore.listeners.isEmpty()); - } - - @Test(timeout = 60000) - public void testLogSegmentNamesListenerOnSessionExpired() throws Exception { - int numSegments = 3; - Transaction createTxn = lsmStore.transaction(); - for (int i = 0; i < numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.createLogSegment(createTxn, segment, null); - } - Utils.ioResult(createTxn.execute()); - String rootPath = "/" + runtime.getMethodName(); - List children = zkc.get().getChildren(rootPath, false); - Collections.sort(children); - - final AtomicInteger numNotifications = new AtomicInteger(0); - final List> segmentLists = Lists.newArrayListWithExpectedSize(2); - LogSegmentNamesListener listener = new LogSegmentNamesListener() { - @Override - public void onSegmentsUpdated(Versioned> segments) { - logger.info("Received segments : {}", segments); - segmentLists.add(segments.getValue()); - numNotifications.incrementAndGet(); - } - - @Override - public void onLogStreamDeleted() { - // no-op; - } - }; - lsmStore.getLogSegmentNames(rootPath, listener); - assertEquals(1, lsmStore.listeners.size()); - assertTrue("Should contain listener", lsmStore.listeners.containsKey(rootPath)); - assertTrue("Should contain listener", lsmStore.listeners.get(rootPath).containsKey(listener)); - while (numNotifications.get() < 1) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive one segment list update", - 1, numNotifications.get()); - List firstSegmentList = segmentLists.get(0); - Collections.sort(firstSegmentList); - assertEquals("List of segments should be same", - children, firstSegmentList); - - ZooKeeperClientUtils.expireSession(zkc, - BKNamespaceDriver.getZKServersFromDLUri(uri), conf.getZKSessionTimeoutMilliseconds()); - - logger.info("Create another {} segments.", numSegments); - - // create another log segment, it should trigger segment list updated - Transaction anotherCreateTxn = lsmStore.transaction(); - for (int i = numSegments; i < 2 * numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.createLogSegment(anotherCreateTxn, segment, null); - } - Utils.ioResult(anotherCreateTxn.execute()); - List newChildren = zkc.get().getChildren(rootPath, false); - Collections.sort(newChildren); - logger.info("All log segments become {}", newChildren); - while (numNotifications.get() < 2) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive third segment list update", - 2, numNotifications.get()); - List thirdSegmentList = segmentLists.get(1); - Collections.sort(thirdSegmentList); - assertEquals("List of segments should be updated", - 2 * numSegments, thirdSegmentList.size()); - assertEquals("List of segments should be updated", - newChildren, thirdSegmentList); - } - - @Test(timeout = 60000) - public void testLogSegmentNamesListenerOnDeletingLogStream() throws Exception { - int numSegments = 3; - Transaction createTxn = lsmStore.transaction(); - for (int i = 0; i < numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.createLogSegment(createTxn, segment, null); - } - Utils.ioResult(createTxn.execute()); - String rootPath = "/" + runtime.getMethodName(); - List children = zkc.get().getChildren(rootPath, false); - Collections.sort(children); - - final AtomicInteger numNotifications = new AtomicInteger(0); - final List> segmentLists = Lists.newArrayListWithExpectedSize(2); - final CountDownLatch deleteLatch = new CountDownLatch(1); - LogSegmentNamesListener listener = new LogSegmentNamesListener() { - @Override - public void onSegmentsUpdated(Versioned> segments) { - logger.info("Received segments : {}", segments); - segmentLists.add(segments.getValue()); - numNotifications.incrementAndGet(); - } - - @Override - public void onLogStreamDeleted() { - deleteLatch.countDown(); - } - }; - lsmStore.getLogSegmentNames(rootPath, listener); - assertEquals(1, lsmStore.listeners.size()); - assertTrue("Should contain listener", lsmStore.listeners.containsKey(rootPath)); - assertTrue("Should contain listener", lsmStore.listeners.get(rootPath).containsKey(listener)); - while (numNotifications.get() < 1) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive one segment list update", - 1, numNotifications.get()); - List firstSegmentList = segmentLists.get(0); - Collections.sort(firstSegmentList); - assertEquals("List of segments should be same", - children, firstSegmentList); - - // delete all log segments, it should trigger segment list updated - Transaction deleteTxn = lsmStore.transaction(); - for (int i = 0; i < numSegments; i++) { - LogSegmentMetadata segment = createLogSegment(i); - lsmStore.deleteLogSegment(deleteTxn, segment, null); - } - Utils.ioResult(deleteTxn.execute()); - List newChildren = zkc.get().getChildren(rootPath, false); - Collections.sort(newChildren); - while (numNotifications.get() < 2) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals("Should receive second segment list update", - 2, numNotifications.get()); - List secondSegmentList = segmentLists.get(1); - Collections.sort(secondSegmentList); - assertEquals("List of segments should be updated", - 0, secondSegmentList.size()); - assertEquals("List of segments should be updated", - newChildren, secondSegmentList); - - // delete the root path - zkc.get().delete(rootPath, -1); - while (!lsmStore.listeners.isEmpty()) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertTrue("listener should be removed after root path is deleted", - lsmStore.listeners.isEmpty()); - deleteLatch.await(); - } - - @Test(timeout = 60000) - public void testStoreMaxLogSegmentSequenceNumber() throws Exception { - Transaction updateTxn = lsmStore.transaction(); - Versioned value = new Versioned(999L, new LongVersion(0)); - final CompletableFuture result = new CompletableFuture(); - LogMetadata metadata = mock(LogMetadata.class); - when(metadata.getLogSegmentsPath()).thenReturn(rootZkPath); - lsmStore.storeMaxLogSegmentSequenceNumber(updateTxn, metadata, value, - new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - result.complete(r); - } - - @Override - public void onAbort(Throwable t) { - result.completeExceptionally(t); - } - }); - Utils.ioResult(updateTxn.execute()); - assertEquals(1L, ((LongVersion) Utils.ioResult(result)).getLongVersion()); - Stat stat = new Stat(); - byte[] data = zkc.get().getData(rootZkPath, false, stat); - assertEquals(999L, DLUtils.deserializeLogSegmentSequenceNumber(data)); - assertEquals(1, stat.getVersion()); - } - - @Test(timeout = 60000) - public void testStoreMaxLogSegmentSequenceNumberBadVersion() throws Exception { - Transaction updateTxn = lsmStore.transaction(); - Versioned value = new Versioned(999L, new LongVersion(10)); - final CompletableFuture result = new CompletableFuture(); - LogMetadata metadata = mock(LogMetadata.class); - when(metadata.getLogSegmentsPath()).thenReturn(rootZkPath); - lsmStore.storeMaxLogSegmentSequenceNumber(updateTxn, metadata, value, - new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - result.complete(r); - } - - @Override - public void onAbort(Throwable t) { - result.completeExceptionally(t); - } - }); - try { - Utils.ioResult(updateTxn.execute()); - fail("Should fail on storing log segment sequence number if providing bad version"); - } catch (ZKException zke) { - assertEquals(KeeperException.Code.BADVERSION, zke.getKeeperExceptionCode()); - } - try { - Utils.ioResult(result); - fail("Should fail on storing log segment sequence number if providing bad version"); - } catch (ZKException ze) { - assertEquals(KeeperException.Code.BADVERSION, ze.getKeeperExceptionCode()); - } - Stat stat = new Stat(); - byte[] data = zkc.get().getData(rootZkPath, false, stat); - assertEquals(0, stat.getVersion()); - assertEquals(0, data.length); - } - - @Test(timeout = 60000) - public void testStoreMaxLogSegmentSequenceNumberOnNonExistentPath() throws Exception { - Transaction updateTxn = lsmStore.transaction(); - Versioned value = new Versioned(999L, new LongVersion(10)); - final CompletableFuture result = new CompletableFuture(); - String nonExistentPath = rootZkPath + "/non-existent"; - LogMetadata metadata = mock(LogMetadata.class); - when(metadata.getLogSegmentsPath()).thenReturn(nonExistentPath); - lsmStore.storeMaxLogSegmentSequenceNumber(updateTxn, metadata, value, - new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - result.complete(r); - } - - @Override - public void onAbort(Throwable t) { - result.completeExceptionally(t); - } - }); - try { - Utils.ioResult(updateTxn.execute()); - fail("Should fail on storing log segment sequence number if path doesn't exist"); - } catch (ZKException zke) { - assertEquals(KeeperException.Code.NONODE, zke.getKeeperExceptionCode()); - } - try { - Utils.ioResult(result); - fail("Should fail on storing log segment sequence number if path doesn't exist"); - } catch (ZKException ke) { - assertEquals(KeeperException.Code.NONODE, ke.getKeeperExceptionCode()); - } - } - - @Test(timeout = 60000) - public void testStoreMaxTxnId() throws Exception { - Transaction updateTxn = lsmStore.transaction(); - Versioned value = new Versioned(999L, new LongVersion(0)); - final CompletableFuture result = new CompletableFuture(); - LogMetadataForWriter metadata = mock(LogMetadataForWriter.class); - when(metadata.getMaxTxIdPath()).thenReturn(rootZkPath); - lsmStore.storeMaxTxnId(updateTxn, metadata, value, - new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - result.complete(r); - } - - @Override - public void onAbort(Throwable t) { - result.completeExceptionally(t); - } - }); - Utils.ioResult(updateTxn.execute()); - assertEquals(1L, ((LongVersion) Utils.ioResult(result)).getLongVersion()); - Stat stat = new Stat(); - byte[] data = zkc.get().getData(rootZkPath, false, stat); - assertEquals(999L, DLUtils.deserializeTransactionId(data)); - assertEquals(1, stat.getVersion()); - } - - @Test(timeout = 60000) - public void testStoreMaxTxnIdBadVersion() throws Exception { - Transaction updateTxn = lsmStore.transaction(); - Versioned value = new Versioned(999L, new LongVersion(10)); - final CompletableFuture result = new CompletableFuture(); - LogMetadataForWriter metadata = mock(LogMetadataForWriter.class); - when(metadata.getMaxTxIdPath()).thenReturn(rootZkPath); - lsmStore.storeMaxTxnId(updateTxn, metadata, value, - new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - result.complete(r); - } - - @Override - public void onAbort(Throwable t) { - result.completeExceptionally(t); - } - }); - try { - Utils.ioResult(updateTxn.execute()); - fail("Should fail on storing log record transaction id if providing bad version"); - } catch (ZKException zke) { - assertEquals(KeeperException.Code.BADVERSION, zke.getKeeperExceptionCode()); - } - try { - Utils.ioResult(result); - fail("Should fail on storing log record transaction id if providing bad version"); - } catch (ZKException ze) { - assertEquals(KeeperException.Code.BADVERSION, ze.getKeeperExceptionCode()); - } - Stat stat = new Stat(); - byte[] data = zkc.get().getData(rootZkPath, false, stat); - assertEquals(0, stat.getVersion()); - assertEquals(0, data.length); - } - - @Test(timeout = 60000) - public void testStoreMaxTxnIdOnNonExistentPath() throws Exception { - Transaction updateTxn = lsmStore.transaction(); - Versioned value = new Versioned(999L, new LongVersion(10)); - final CompletableFuture result = new CompletableFuture(); - String nonExistentPath = rootZkPath + "/non-existent"; - LogMetadataForWriter metadata = mock(LogMetadataForWriter.class); - when(metadata.getMaxTxIdPath()).thenReturn(nonExistentPath); - lsmStore.storeMaxTxnId(updateTxn, metadata, value, - new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - result.complete(r); - } - - @Override - public void onAbort(Throwable t) { - result.completeExceptionally(t); - } - }); - try { - Utils.ioResult(updateTxn.execute()); - fail("Should fail on storing log record transaction id if path doesn't exist"); - } catch (ZKException zke) { - assertEquals(KeeperException.Code.NONODE, zke.getKeeperExceptionCode()); - } - try { - Utils.ioResult(result); - fail("Should fail on storing log record transaction id if path doesn't exist"); - } catch (ZKException ze) { - assertEquals(KeeperException.Code.NONODE, ze.getKeeperExceptionCode()); - } - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKNamespaceWatcher.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKNamespaceWatcher.java deleted file mode 100644 index 3143e7ff4a1..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/TestZKNamespaceWatcher.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Sets; -import java.net.URI; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClientUtils; -import org.apache.distributedlog.callback.NamespaceListener; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - - - -/** - * Test ZK Namespace Watcher. - */ -public class TestZKNamespaceWatcher extends TestDistributedLogBase { - - private static final int zkSessionTimeoutMs = 2000; - - @Rule - public TestName runtime = new TestName(); - protected final DistributedLogConfiguration baseConf = - new DistributedLogConfiguration(); - protected ZooKeeperClient zkc; - protected OrderedScheduler scheduler; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createDLMURI("/")) - .sessionTimeoutMs(zkSessionTimeoutMs) - .build(); - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-zk-namespace-watcher") - .numThreads(1) - .build(); - } - - @After - public void teardown() throws Exception { - if (null != zkc) { - zkc.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - } - - private void createLogInNamespace(URI uri, String logName) throws Exception { - String logPath = uri.getPath() + "/" + logName; - Utils.zkCreateFullPathOptimistic(zkc, logPath, new byte[0], - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } - - private void deleteLogInNamespace(URI uri, String logName) throws Exception { - String logPath = uri.getPath() + "/" + logName; - zkc.get().delete(logPath, -1); - } - - @Test(timeout = 60000) - public void testNamespaceListener() throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - zkc.get().create(uri.getPath(), new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.addConfiguration(baseConf); - ZKNamespaceWatcher watcher = new ZKNamespaceWatcher(conf, uri, zkc, scheduler); - final CountDownLatch[] latches = new CountDownLatch[10]; - for (int i = 0; i < 10; i++) { - latches[i] = new CountDownLatch(1); - } - final AtomicInteger numUpdates = new AtomicInteger(0); - final AtomicReference> receivedLogs = new AtomicReference>(null); - watcher.registerListener(new NamespaceListener() { - @Override - public void onStreamsChanged(Iterator streams) { - Set streamSet = Sets.newHashSet(streams); - int updates = numUpdates.incrementAndGet(); - receivedLogs.set(streamSet); - latches[updates - 1].countDown(); - } - }); - // first update - final Set expectedLogs = Sets.newHashSet(); - latches[0].await(); - validateReceivedLogs(expectedLogs, receivedLogs.get()); - - // create test1 - expectedLogs.add("test1"); - createLogInNamespace(uri, "test1"); - latches[1].await(); - validateReceivedLogs(expectedLogs, receivedLogs.get()); - - // create invalid log - createLogInNamespace(uri, ".test1"); - latches[2].await(); - validateReceivedLogs(expectedLogs, receivedLogs.get()); - - // create test2 - expectedLogs.add("test2"); - createLogInNamespace(uri, "test2"); - latches[3].await(); - validateReceivedLogs(expectedLogs, receivedLogs.get()); - - // delete test1 - expectedLogs.remove("test1"); - deleteLogInNamespace(uri, "test1"); - latches[4].await(); - validateReceivedLogs(expectedLogs, receivedLogs.get()); - } - - private void validateReceivedLogs(Set expectedLogs, Set receivedLogs) { - assertTrue(Sets.difference(expectedLogs, receivedLogs).isEmpty()); - } - - @Test(timeout = 60000) - public void testSessionExpired() throws Exception { - URI uri = createDLMURI("/" + runtime.getMethodName()); - zkc.get().create(uri.getPath(), new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.addConfiguration(baseConf); - ZKNamespaceWatcher watcher = new ZKNamespaceWatcher(conf, uri, zkc, scheduler); - final CountDownLatch[] latches = new CountDownLatch[10]; - for (int i = 0; i < 10; i++) { - latches[i] = new CountDownLatch(1); - } - final AtomicInteger numUpdates = new AtomicInteger(0); - final AtomicReference> receivedLogs = new AtomicReference>(null); - watcher.registerListener(new NamespaceListener() { - @Override - public void onStreamsChanged(Iterator streams) { - Set streamSet = Sets.newHashSet(streams); - int updates = numUpdates.incrementAndGet(); - receivedLogs.set(streamSet); - latches[updates - 1].countDown(); - } - }); - latches[0].await(); - createLogInNamespace(uri, "test1"); - latches[1].await(); - createLogInNamespace(uri, "test2"); - latches[2].await(); - assertEquals(2, receivedLogs.get().size()); - ZooKeeperClientUtils.expireSession(zkc, BKNamespaceDriver.getZKServersFromDLUri(uri), zkSessionTimeoutMs); - latches[3].await(); - assertEquals(2, receivedLogs.get().size()); - createLogInNamespace(uri, "test3"); - latches[4].await(); - assertEquals(3, receivedLogs.get().size()); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/federated/TestFederatedZKLogMetadataStore.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/federated/TestFederatedZKLogMetadataStore.java deleted file mode 100644 index d4282baf6e4..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/federated/TestFederatedZKLogMetadataStore.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl.federated; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import java.net.URI; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClientUtils; -import org.apache.distributedlog.callback.NamespaceListener; -import org.apache.distributedlog.exceptions.LogExistsException; -import org.apache.distributedlog.exceptions.UnexpectedException; -import org.apache.distributedlog.impl.BKNamespaceDriver; -import org.apache.distributedlog.metadata.LogMetadataStore; -import org.apache.distributedlog.util.Utils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - - - - -/** - * Test ZK based metadata store. - */ -public class TestFederatedZKLogMetadataStore extends TestDistributedLogBase { - - private static final int zkSessionTimeoutMs = 2000; - private static final int maxLogsPerSubnamespace = 10; - - static class TestNamespaceListener implements NamespaceListener { - - final CountDownLatch doneLatch = new CountDownLatch(1); - final AtomicReference> resultHolder = new AtomicReference>(); - - @Override - public void onStreamsChanged(Iterator streams) { - resultHolder.set(streams); - if (streams.hasNext()) { - doneLatch.countDown(); - } - } - - Iterator getResult() { - return resultHolder.get(); - } - - void waitForDone() throws InterruptedException { - doneLatch.await(); - } - } - - static class TestNamespaceListenerWithExpectedSize implements NamespaceListener { - - final int expectedSize; - final CountDownLatch doneLatch = new CountDownLatch(1); - final AtomicReference> resultHolder = new AtomicReference>(); - - TestNamespaceListenerWithExpectedSize(int expectedSize) { - this.expectedSize = expectedSize; - } - - Set getResult() { - return resultHolder.get(); - } - - @Override - public void onStreamsChanged(Iterator logsIter) { - List logList = Lists.newArrayList(logsIter); - if (logList.size() < expectedSize) { - return; - } - resultHolder.set(Sets.newTreeSet(logList)); - doneLatch.countDown(); - } - - void waitForDone() throws InterruptedException { - doneLatch.await(); - } - } - - @Rule - public TestName runtime = new TestName(); - protected final DistributedLogConfiguration baseConf = - new DistributedLogConfiguration() - .setFederatedMaxLogsPerSubnamespace(maxLogsPerSubnamespace); - protected ZooKeeperClient zkc; - protected FederatedZKLogMetadataStore metadataStore; - protected OrderedScheduler scheduler; - protected URI uri; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createDLMURI("/")) - .sessionTimeoutMs(zkSessionTimeoutMs) - .build(); - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-zk-logmetadata-store") - .numThreads(2) - .build(); - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.addConfiguration(baseConf); - this.uri = createDLMURI("/" + runtime.getMethodName()); - FederatedZKLogMetadataStore.createFederatedNamespace(uri, zkc); - metadataStore = new FederatedZKLogMetadataStore(conf, uri, zkc, scheduler); - } - - @After - public void teardown() throws Exception { - if (null != zkc) { - zkc.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - } - - private void deleteLog(String logName) throws Exception { - Optional logUriOptional = Utils.ioResult(metadataStore.getLogLocation(logName)); - assertTrue(logUriOptional.isPresent()); - URI logUri = logUriOptional.get(); - zkc.get().delete(logUri.getPath() + "/" + logName, -1); - } - - @Test(timeout = 60000) - public void testBasicOperations() throws Exception { - TestNamespaceListener listener = new TestNamespaceListener(); - metadataStore.registerNamespaceListener(listener); - String logName = "test-log-1"; - URI logUri = Utils.ioResult(metadataStore.createLog(logName)); - assertEquals(uri, logUri); - Optional logLocation = Utils.ioResult(metadataStore.getLogLocation(logName)); - assertTrue(logLocation.isPresent()); - assertEquals(uri, logLocation.get()); - Optional notExistLogLocation = Utils.ioResult(metadataStore.getLogLocation("non-existent-log")); - assertFalse(notExistLogLocation.isPresent()); - // listener should receive notification - listener.waitForDone(); - Iterator logsIter = listener.getResult(); - assertTrue(logsIter.hasNext()); - assertEquals(logName, logsIter.next()); - assertFalse(logsIter.hasNext()); - // get logs should return the log - Iterator newLogsIter = Utils.ioResult(metadataStore.getLogs("")); - assertTrue(newLogsIter.hasNext()); - assertEquals(logName, newLogsIter.next()); - assertFalse(newLogsIter.hasNext()); - } - - @Test(timeout = 60000) - public void testMultipleListeners() throws Exception { - TestNamespaceListener listener1 = new TestNamespaceListener(); - TestNamespaceListener listener2 = new TestNamespaceListener(); - metadataStore.registerNamespaceListener(listener1); - metadataStore.registerNamespaceListener(listener2); - String logName = "test-multiple-listeners"; - URI logUri = Utils.ioResult(metadataStore.createLog(logName)); - assertEquals(uri, logUri); - listener1.waitForDone(); - listener2.waitForDone(); - Iterator logsIter1 = listener1.getResult(); - Iterator logsIter2 = listener2.getResult(); - assertTrue(Iterators.elementsEqual(logsIter1, logsIter2)); - } - - @Test(timeout = 60000) - public void testCreateLog() throws Exception { - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.addConfiguration(baseConf); - ZooKeeperClient anotherZkc = TestZooKeeperClientBuilder.newBuilder() - .uri(uri) - .sessionTimeoutMs(zkSessionTimeoutMs) - .build(); - FederatedZKLogMetadataStore anotherMetadataStore = - new FederatedZKLogMetadataStore(conf, uri, anotherZkc, scheduler); - for (int i = 0; i < 2 * maxLogsPerSubnamespace; i++) { - LogMetadataStore createStore, checkStore; - if (i % 2 == 0) { - createStore = metadataStore; - checkStore = anotherMetadataStore; - } else { - createStore = anotherMetadataStore; - checkStore = metadataStore; - } - String logName = "test-create-log-" + i; - URI logUri = Utils.ioResult(createStore.createLog(logName)); - Optional logLocation = Utils.ioResult(checkStore.getLogLocation(logName)); - assertTrue("Log " + logName + " doesn't exist", logLocation.isPresent()); - assertEquals("Different log location " + logLocation.get() + " is found", - logUri, logLocation.get()); - } - assertEquals(2, metadataStore.getSubnamespaces().size()); - assertEquals(2, anotherMetadataStore.getSubnamespaces().size()); - } - - @Test(timeout = 60000) - public void testDuplicatedLogs() throws Exception { - DistributedLogConfiguration conf = new DistributedLogConfiguration(); - conf.addConfiguration(baseConf); - - String logName = "test-log"; - Utils.ioResult(metadataStore.createLog(logName)); - - URI subNs1 = Utils.ioResult(metadataStore.createSubNamespace()); - URI subNs2 = Utils.ioResult(metadataStore.createSubNamespace()); - - String duplicatedLogName = "test-duplicated-logs"; - // Create same log in different sub namespaces - metadataStore.createLogInNamespaceSync(subNs1, duplicatedLogName); - metadataStore.createLogInNamespaceSync(subNs2, duplicatedLogName); - - try { - Utils.ioResult(metadataStore.createLog("non-existent-log")); - fail("should throw exception when duplicated log found"); - } catch (UnexpectedException ue) { - // should throw unexpected exception - assertTrue(metadataStore.duplicatedLogFound.get()); - } - try { - Utils.ioResult(metadataStore.getLogLocation(logName)); - fail("should throw exception when duplicated log found"); - } catch (UnexpectedException ue) { - // should throw unexpected exception - assertTrue(metadataStore.duplicatedLogFound.get()); - } - try { - Utils.ioResult(metadataStore.getLogLocation("non-existent-log")); - fail("should throw exception when duplicated log found"); - } catch (UnexpectedException ue) { - // should throw unexpected exception - assertTrue(metadataStore.duplicatedLogFound.get()); - } - try { - Utils.ioResult(metadataStore.getLogLocation(duplicatedLogName)); - fail("should throw exception when duplicated log found"); - } catch (UnexpectedException ue) { - // should throw unexpected exception - assertTrue(metadataStore.duplicatedLogFound.get()); - } - try { - Utils.ioResult(metadataStore.getLogs("")); - fail("should throw exception when duplicated log found"); - } catch (UnexpectedException ue) { - // should throw unexpected exception - assertTrue(metadataStore.duplicatedLogFound.get()); - } - } - - @Test(timeout = 60000) - public void testGetLogLocationWhenCacheMissed() throws Exception { - String logName = "test-get-location-when-cache-missed"; - URI logUri = Utils.ioResult(metadataStore.createLog(logName)); - assertEquals(uri, logUri); - metadataStore.removeLogFromCache(logName); - Optional logLocation = Utils.ioResult(metadataStore.getLogLocation(logName)); - assertTrue(logLocation.isPresent()); - assertEquals(logUri, logLocation.get()); - } - - @Test(timeout = 60000, expected = LogExistsException.class) - public void testCreateLogWhenCacheMissed() throws Exception { - String logName = "test-create-log-when-cache-missed"; - URI logUri = Utils.ioResult(metadataStore.createLog(logName)); - assertEquals(uri, logUri); - metadataStore.removeLogFromCache(logName); - Utils.ioResult(metadataStore.createLog(logName)); - } - - @Test(timeout = 60000, expected = LogExistsException.class) - public void testCreateLogWhenLogExists() throws Exception { - String logName = "test-create-log-when-log-exists"; - URI logUri = Utils.ioResult(metadataStore.createLog(logName)); - assertEquals(uri, logUri); - Utils.ioResult(metadataStore.createLog(logName)); - } - - private Set createLogs(int numLogs, String prefix) throws Exception { - Set expectedLogs = Sets.newTreeSet(); - for (int i = 0; i < numLogs; i++) { - String logName = prefix + i; - Utils.ioResult(metadataStore.createLog(logName)); - expectedLogs.add(logName); - } - return expectedLogs; - } - - private Set createLogs(URI uri, int numLogs, String prefix) throws Exception { - Set expectedLogs = Sets.newTreeSet(); - for (int i = 0; i < numLogs; i++) { - String logName = prefix + i; - metadataStore.createLogInNamespaceSync(uri, logName); - expectedLogs.add(logName); - } - return expectedLogs; - } - - @Test(timeout = 60000) - public void testGetLogs() throws Exception { - int numLogs = 3 * maxLogsPerSubnamespace; - Set expectedLogs = createLogs(numLogs, "test-get-logs"); - Set receivedLogs; - do { - TimeUnit.MILLISECONDS.sleep(20); - receivedLogs = new TreeSet(); - Iterator logs = Utils.ioResult(metadataStore.getLogs("")); - receivedLogs.addAll(Lists.newArrayList(logs)); - } while (receivedLogs.size() < numLogs); - assertEquals(numLogs, receivedLogs.size()); - assertTrue(Sets.difference(expectedLogs, receivedLogs).isEmpty()); - } - - @Test(timeout = 60000) - public void testNamespaceListener() throws Exception { - int numLogs = 3 * maxLogsPerSubnamespace; - TestNamespaceListenerWithExpectedSize listener = new TestNamespaceListenerWithExpectedSize(numLogs); - metadataStore.registerNamespaceListener(listener); - Set expectedLogs = createLogs(numLogs, "test-namespace-listener"); - listener.waitForDone(); - Set receivedLogs = listener.getResult(); - assertEquals(numLogs, receivedLogs.size()); - assertTrue(Sets.difference(expectedLogs, receivedLogs).isEmpty()); - - Random r = new Random(System.currentTimeMillis()); - int logId = r.nextInt(numLogs); - String logName = "test-namespace-listener" + logId; - TestNamespaceListener deleteListener = new TestNamespaceListener(); - metadataStore.registerNamespaceListener(deleteListener); - deleteLog(logName); - deleteListener.waitForDone(); - Set logsAfterDeleted = Sets.newTreeSet(Lists.newArrayList(deleteListener.getResult())); - assertEquals(numLogs - 1, logsAfterDeleted.size()); - expectedLogs.remove(logName); - assertTrue(Sets.difference(expectedLogs, receivedLogs).isEmpty()); - } - - @Test(timeout = 60000) - public void testCreateLogPickingFirstAvailableSubNamespace() throws Exception { - URI subNs1 = Utils.ioResult(metadataStore.createSubNamespace()); - URI subNs2 = Utils.ioResult(metadataStore.createSubNamespace()); - - Set logs0 = createLogs(uri, maxLogsPerSubnamespace - 1, "test-ns0-"); - Set logs1 = createLogs(subNs1, maxLogsPerSubnamespace, "test-ns1-"); - Set logs2 = createLogs(subNs2, maxLogsPerSubnamespace, "test-ns2-"); - Set allLogs = Sets.newTreeSet(); - allLogs.addAll(logs0); - allLogs.addAll(logs1); - allLogs.addAll(logs2); - - // make sure the metadata store saw all 29 logs - Set receivedLogs; - do { - TimeUnit.MILLISECONDS.sleep(20); - receivedLogs = new TreeSet(); - Iterator logs = Utils.ioResult(metadataStore.getLogs("")); - receivedLogs.addAll(Lists.newArrayList(logs)); - } while (receivedLogs.size() < 3 * maxLogsPerSubnamespace - 1); - - TestNamespaceListenerWithExpectedSize listener = - new TestNamespaceListenerWithExpectedSize(3 * maxLogsPerSubnamespace + 1); - metadataStore.registerNamespaceListener(listener); - - Set uris = Utils.ioResult(metadataStore.fetchSubNamespaces(null)); - assertEquals(3, uris.size()); - String testLogName = "test-pick-first-available-ns"; - URI createdURI = Utils.ioResult(metadataStore.createLog(testLogName)); - allLogs.add(testLogName); - assertEquals(uri, createdURI); - uris = Utils.ioResult(metadataStore.fetchSubNamespaces(null)); - assertEquals(3, uris.size()); - testLogName = "test-create-new-ns"; - URI newURI = Utils.ioResult(metadataStore.createLog(testLogName)); - allLogs.add(testLogName); - assertFalse(uris.contains(newURI)); - uris = Utils.ioResult(metadataStore.fetchSubNamespaces(null)); - assertEquals(4, uris.size()); - - listener.waitForDone(); - receivedLogs = listener.getResult(); - assertEquals(3 * maxLogsPerSubnamespace + 1, receivedLogs.size()); - assertEquals(allLogs, receivedLogs); - } - - @Test(timeout = 60000) - public void testZooKeeperSessionExpired() throws Exception { - Set allLogs = createLogs(2 * maxLogsPerSubnamespace, "test-zookeeper-session-expired-"); - TestNamespaceListenerWithExpectedSize listener = - new TestNamespaceListenerWithExpectedSize(2 * maxLogsPerSubnamespace + 1); - metadataStore.registerNamespaceListener(listener); - ZooKeeperClientUtils.expireSession(zkc, BKNamespaceDriver.getZKServersFromDLUri(uri), zkSessionTimeoutMs); - String testLogName = "test-log-name"; - allLogs.add(testLogName); - - DistributedLogConfiguration anotherConf = new DistributedLogConfiguration(); - anotherConf.addConfiguration(baseConf); - ZooKeeperClient anotherZkc = TestZooKeeperClientBuilder.newBuilder() - .uri(uri) - .sessionTimeoutMs(zkSessionTimeoutMs) - .build(); - FederatedZKLogMetadataStore anotherMetadataStore = - new FederatedZKLogMetadataStore(anotherConf, uri, anotherZkc, scheduler); - Utils.ioResult(anotherMetadataStore.createLog(testLogName)); - - listener.waitForDone(); - Set receivedLogs = listener.getResult(); - assertEquals(2 * maxLogsPerSubnamespace + 1, receivedLogs.size()); - assertEquals(allLogs, receivedLogs); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/logsegment/TestBKLogSegmentEntryReader.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/logsegment/TestBKLogSegmentEntryReader.java deleted file mode 100644 index dd37b3cef5e..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/logsegment/TestBKLogSegmentEntryReader.java +++ /dev/null @@ -1,567 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl.logsegment; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.distributedlog.BookKeeperClient; -import org.apache.distributedlog.BookKeeperClientBuilder; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.Entry; -import org.apache.distributedlog.LogRecord; -import org.apache.distributedlog.LogRecordWithDLSN; -import org.apache.distributedlog.LogSegmentMetadata; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClientBuilder; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.exceptions.EndOfLogSegmentException; -import org.apache.distributedlog.exceptions.ReadCancelledException; -import org.apache.distributedlog.injector.AsyncFailureInjector; -import org.apache.distributedlog.logsegment.LogSegmentEntryStore; -import org.apache.distributedlog.util.ConfUtils; -import org.apache.distributedlog.util.Utils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - - - - -/** - * Test Case for {@link BKLogSegmentEntryReader}. - */ -public class TestBKLogSegmentEntryReader extends TestDistributedLogBase { - - @Rule - public TestName runtime = new TestName(); - private OrderedScheduler scheduler; - private BookKeeperClient bkc; - private ZooKeeperClient zkc; - - @Before - public void setup() throws Exception { - super.setup(); - zkc = ZooKeeperClientBuilder.newBuilder() - .name("test-zk") - .zkServers(bkutil.getZkServers()) - .sessionTimeoutMs(conf.getZKSessionTimeoutMilliseconds()) - .zkAclId(conf.getZkAclId()) - .build(); - bkc = BookKeeperClientBuilder.newBuilder() - .name("test-bk") - .dlConfig(conf) - .ledgersPath("/ledgers") - .zkServers(bkutil.getZkServers()) - .build(); - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-bk-logsegment-entry-reader") - .numThreads(1) - .build(); - } - - @After - public void teardown() throws Exception { - if (null != bkc) { - bkc.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - if (null != zkc) { - zkc.close(); - } - super.teardown(); - } - - BKLogSegmentEntryReader createEntryReader(LogSegmentMetadata segment, - long startEntryId, - DistributedLogConfiguration conf) - throws Exception { - LogSegmentEntryStore store = new BKLogSegmentEntryStore( - conf, - ConfUtils.getConstDynConf(conf), - zkc, - bkc, - scheduler, - null, - NullStatsLogger.INSTANCE, - AsyncFailureInjector.NULL); - return (BKLogSegmentEntryReader) Utils.ioResult(store.openReader(segment, startEntryId)); - } - - void generateCompletedLogSegments(DistributedLogManager dlm, - DistributedLogConfiguration conf, - long numCompletedSegments, - long segmentSize) throws Exception { - long txid = 1L; - for (long i = 0; i < numCompletedSegments; i++) { - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - for (long j = 1; j <= segmentSize; j++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txid++))); - LogRecord ctrlRecord = DLMTestUtil.getLogRecordInstance(txid); - ctrlRecord.setControl(); - Utils.ioResult(writer.write(ctrlRecord)); - } - Utils.close(writer); - } - } - - AsyncLogWriter createInprogressLogSegment(DistributedLogManager dlm, - DistributedLogConfiguration conf, - long segmentSize) throws Exception { - AsyncLogWriter writer = Utils.ioResult(dlm.openAsyncLogWriter()); - for (long i = 1L; i <= segmentSize; i++) { - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(i))); - LogRecord ctrlRecord = DLMTestUtil.getLogRecordInstance(i); - ctrlRecord.setControl(); - Utils.ioResult(writer.write(ctrlRecord)); - } - return writer; - } - - @Test(timeout = 60000) - public void testReadEntriesFromCompleteLogSegment() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setNumPrefetchEntriesPerLogSegment(10); - confLocal.setMaxPrefetchEntriesPerLogSegment(10); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - generateCompletedLogSegments(dlm, confLocal, 1, 20); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - BKLogSegmentEntryReader reader = createEntryReader(segments.get(0), 0, confLocal); - reader.start(); - boolean done = false; - long txId = 1L; - long entryId = 0L; - while (!done) { - Entry.Reader entryReader; - try { - entryReader = Utils.ioResult(reader.readNext(1)).get(0); - } catch (EndOfLogSegmentException eol) { - done = true; - continue; - } - LogRecordWithDLSN record = entryReader.nextRecord(); - while (null != record) { - if (!record.isControl()) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(txId, record.getTransactionId()); - ++txId; - } - DLSN dlsn = record.getDlsn(); - assertEquals(1L, dlsn.getLogSegmentSequenceNo()); - assertEquals(entryId, dlsn.getEntryId()); - record = entryReader.nextRecord(); - } - ++entryId; - } - assertEquals(21, txId); - assertFalse(reader.hasCaughtUpOnInprogress()); - Utils.close(reader); - } - - @Test(timeout = 60000) - public void testCloseReaderToCancelPendingReads() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setNumPrefetchEntriesPerLogSegment(10); - confLocal.setMaxPrefetchEntriesPerLogSegment(10); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - DLMTestUtil.generateCompletedLogSegments(dlm, confLocal, 1, 20); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - BKLogSegmentEntryReader reader = createEntryReader(segments.get(0), 0, confLocal); - List>> futures = Lists.newArrayList(); - for (int i = 0; i < 5; i++) { - futures.add(reader.readNext(1)); - } - assertFalse("Reader should not be closed yet", reader.isClosed()); - Utils.close(reader); - for (CompletableFuture> future : futures) { - try { - Utils.ioResult(future); - fail("The read request should be cancelled"); - } catch (ReadCancelledException rce) { - // expected - } - } - assertFalse(reader.hasCaughtUpOnInprogress()); - assertTrue("Reader should be closed yet", reader.isClosed()); - } - - @Test(timeout = 60000) - public void testMaxPrefetchEntriesSmallBatch() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setNumPrefetchEntriesPerLogSegment(2); - confLocal.setMaxPrefetchEntriesPerLogSegment(10); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - generateCompletedLogSegments(dlm, confLocal, 1, 20); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - BKLogSegmentEntryReader reader = createEntryReader(segments.get(0), 0, confLocal); - reader.start(); - - // wait for the read ahead entries to become available - while (reader.readAheadEntries.size() < 10) { - TimeUnit.MILLISECONDS.sleep(10); - } - - long txId = 1L; - long entryId = 0L; - - assertEquals(10, reader.readAheadEntries.size()); - assertEquals(10, reader.getNextEntryId()); - assertFalse(reader.hasCaughtUpOnInprogress()); - // read first entry - Entry.Reader entryReader = Utils.ioResult(reader.readNext(1)).get(0); - LogRecordWithDLSN record = entryReader.nextRecord(); - while (null != record) { - if (!record.isControl()) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(txId, record.getTransactionId()); - ++txId; - } - DLSN dlsn = record.getDlsn(); - assertEquals(1L, dlsn.getLogSegmentSequenceNo()); - assertEquals(entryId, dlsn.getEntryId()); - record = entryReader.nextRecord(); - } - ++entryId; - assertEquals(2L, txId); - // wait for the read ahead entries to become 10 again - while (reader.readAheadEntries.size() < 10) { - TimeUnit.MILLISECONDS.sleep(10); - } - - assertEquals(10, reader.readAheadEntries.size()); - assertEquals(11, reader.getNextEntryId()); - assertFalse(reader.hasCaughtUpOnInprogress()); - - Utils.close(reader); - } - - @Test(timeout = 60000) - public void testMaxPrefetchEntriesLargeBatch() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setNumPrefetchEntriesPerLogSegment(10); - confLocal.setMaxPrefetchEntriesPerLogSegment(5); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - generateCompletedLogSegments(dlm, confLocal, 1, 20); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - BKLogSegmentEntryReader reader = createEntryReader(segments.get(0), 0, confLocal); - reader.start(); - - // wait for the read ahead entries to become available - while (reader.readAheadEntries.size() < 5) { - TimeUnit.MILLISECONDS.sleep(10); - } - - long txId = 1L; - long entryId = 0L; - - assertEquals(5, reader.readAheadEntries.size()); - assertEquals(5, reader.getNextEntryId()); - // read first entry - Entry.Reader entryReader = Utils.ioResult(reader.readNext(1)).get(0); - LogRecordWithDLSN record = entryReader.nextRecord(); - while (null != record) { - if (!record.isControl()) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(txId, record.getTransactionId()); - ++txId; - } - DLSN dlsn = record.getDlsn(); - assertEquals(1L, dlsn.getLogSegmentSequenceNo()); - assertEquals(entryId, dlsn.getEntryId()); - record = entryReader.nextRecord(); - } - ++entryId; - assertEquals(2L, txId); - // wait for the read ahead entries to become 10 again - while (reader.readAheadEntries.size() < 5) { - TimeUnit.MILLISECONDS.sleep(10); - } - - assertEquals(5, reader.readAheadEntries.size()); - assertEquals(6, reader.getNextEntryId()); - assertFalse(reader.hasCaughtUpOnInprogress()); - - Utils.close(reader); - } - - @Test(timeout = 60000) - public void testMaxPrefetchEntriesSmallSegment() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setNumPrefetchEntriesPerLogSegment(10); - confLocal.setMaxPrefetchEntriesPerLogSegment(20); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - generateCompletedLogSegments(dlm, confLocal, 1, 5); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - BKLogSegmentEntryReader reader = createEntryReader(segments.get(0), 0, confLocal); - reader.start(); - - // wait for the read ahead entries to become available - while (reader.readAheadEntries.size() < (reader.getLastAddConfirmed() + 1)) { - TimeUnit.MILLISECONDS.sleep(10); - } - - long txId = 1L; - long entryId = 0L; - - assertEquals((reader.getLastAddConfirmed() + 1), reader.readAheadEntries.size()); - assertEquals((reader.getLastAddConfirmed() + 1), reader.getNextEntryId()); - // read first entry - Entry.Reader entryReader = Utils.ioResult(reader.readNext(1)).get(0); - LogRecordWithDLSN record = entryReader.nextRecord(); - while (null != record) { - if (!record.isControl()) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(txId, record.getTransactionId()); - ++txId; - } - DLSN dlsn = record.getDlsn(); - assertEquals(1L, dlsn.getLogSegmentSequenceNo()); - assertEquals(entryId, dlsn.getEntryId()); - record = entryReader.nextRecord(); - } - ++entryId; - assertEquals(2L, txId); - assertEquals(reader.getLastAddConfirmed(), reader.readAheadEntries.size()); - assertEquals((reader.getLastAddConfirmed() + 1), reader.getNextEntryId()); - assertFalse(reader.hasCaughtUpOnInprogress()); - - Utils.close(reader); - } - - @Test(timeout = 60000) - public void testReadEntriesFromInprogressSegment() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setNumPrefetchEntriesPerLogSegment(20); - confLocal.setMaxPrefetchEntriesPerLogSegment(20); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - AsyncLogWriter writer = createInprogressLogSegment(dlm, confLocal, 5); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - BKLogSegmentEntryReader reader = createEntryReader(segments.get(0), 0, confLocal); - reader.start(); - - long expectedLastAddConfirmed = 8L; - // wait until sending out all prefetch requests - while (reader.readAheadEntries.size() < expectedLastAddConfirmed + 2) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals(expectedLastAddConfirmed + 2, reader.getNextEntryId()); - - long txId = 1L; - long entryId = 0L; - while (true) { - Entry.Reader entryReader = Utils.ioResult(reader.readNext(1)).get(0); - LogRecordWithDLSN record = entryReader.nextRecord(); - while (null != record) { - if (!record.isControl()) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(txId, record.getTransactionId()); - ++txId; - } - DLSN dlsn = record.getDlsn(); - assertEquals(1L, dlsn.getLogSegmentSequenceNo()); - assertEquals(entryId, dlsn.getEntryId()); - record = entryReader.nextRecord(); - } - ++entryId; - if (entryId == expectedLastAddConfirmed + 1) { - break; - } - } - assertEquals(6L, txId); - - CompletableFuture> nextReadFuture = reader.readNext(1); - // write another record to commit previous writes - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId))); - // the long poll will be satisfied - List nextReadEntries = Utils.ioResult(nextReadFuture); - assertEquals(1, nextReadEntries.size()); - assertTrue(reader.hasCaughtUpOnInprogress()); - Entry.Reader entryReader = nextReadEntries.get(0); - LogRecordWithDLSN record = entryReader.nextRecord(); - assertNotNull(record); - assertTrue(record.isControl()); - assertNull(entryReader.nextRecord()); - // once the read is advanced, we will prefetch next record - while (reader.getNextEntryId() <= entryId) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals(entryId + 2, reader.getNextEntryId()); - assertEquals(1, reader.readAheadEntries.size()); - - Utils.close(reader); - Utils.close(writer); - } - - @Test(timeout = 60000) - public void testReadEntriesOnStateChange() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setOutputBufferSize(0); - confLocal.setPeriodicFlushFrequencyMilliSeconds(0); - confLocal.setImmediateFlushEnabled(false); - confLocal.setNumPrefetchEntriesPerLogSegment(20); - confLocal.setMaxPrefetchEntriesPerLogSegment(20); - DistributedLogManager dlm = createNewDLM(confLocal, runtime.getMethodName()); - AsyncLogWriter writer = createInprogressLogSegment(dlm, confLocal, 5); - List segments = dlm.getLogSegments(); - assertEquals(segments.size() + " log segments found, expected to be only one", - 1, segments.size()); - - BKLogSegmentEntryReader reader = createEntryReader(segments.get(0), 0, confLocal); - reader.start(); - - long expectedLastAddConfirmed = 8L; - // wait until sending out all prefetch requests - while (reader.readAheadEntries.size() < expectedLastAddConfirmed + 2) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals(expectedLastAddConfirmed + 2, reader.getNextEntryId()); - - long txId = 1L; - long entryId = 0L; - while (true) { - Entry.Reader entryReader = Utils.ioResult(reader.readNext(1)).get(0); - LogRecordWithDLSN record = entryReader.nextRecord(); - while (null != record) { - if (!record.isControl()) { - DLMTestUtil.verifyLogRecord(record); - assertEquals(txId, record.getTransactionId()); - ++txId; - } - DLSN dlsn = record.getDlsn(); - assertEquals(1L, dlsn.getLogSegmentSequenceNo()); - assertEquals(entryId, dlsn.getEntryId()); - record = entryReader.nextRecord(); - } - ++entryId; - if (entryId == expectedLastAddConfirmed + 1) { - break; - } - } - assertEquals(6L, txId); - - CompletableFuture> nextReadFuture = reader.readNext(1); - // write another record to commit previous writes - Utils.ioResult(writer.write(DLMTestUtil.getLogRecordInstance(txId))); - // the long poll will be satisfied - List nextReadEntries = Utils.ioResult(nextReadFuture); - assertEquals(1, nextReadEntries.size()); - Entry.Reader entryReader = nextReadEntries.get(0); - LogRecordWithDLSN record = entryReader.nextRecord(); - assertNotNull(record); - assertTrue(record.isControl()); - assertNull(entryReader.nextRecord()); - // once the read is advanced, we will prefetch next record - while (reader.getNextEntryId() <= entryId) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals(entryId + 2, reader.getNextEntryId()); - assertEquals(1, reader.readAheadEntries.size()); - - // advance the entry id - ++entryId; - // close the writer, the write will be committed - Utils.close(writer); - entryReader = Utils.ioResult(reader.readNext(1)).get(0); - record = entryReader.nextRecord(); - assertNotNull(record); - assertFalse(record.isControl()); - assertNull(entryReader.nextRecord()); - while (reader.getNextEntryId() <= entryId + 1) { - TimeUnit.MILLISECONDS.sleep(10); - } - assertEquals(entryId + 2, reader.getNextEntryId()); - assertEquals(1, reader.readAheadEntries.size()); - - // get the new log segment - List newSegments = dlm.getLogSegments(); - assertEquals(1, newSegments.size()); - assertFalse(newSegments.get(0).isInProgress()); - reader.onLogSegmentMetadataUpdated(newSegments.get(0)); - // when reader received the new log segments. the outstanding long poll - // should be cancelled and end of log segment should be signaled correctly - try { - // when we closed the log segment, another control record will be - // written, so we loop over the reader until we reach end of log segment. - Utils.ioResult(reader.readNext(1)); - Utils.ioResult(reader.readNext(1)); - fail("Should reach end of log segment"); - } catch (EndOfLogSegmentException eol) { - // expected - } - Utils.close(reader); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStore.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStore.java deleted file mode 100644 index d4a6764a02d..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStore.java +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl.metadata; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.distributedlog.DistributedLogConstants.EMPTY_BYTES; -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.checkLogMetadataPaths; -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.getLog; -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.getLogSegments; -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.getMissingPaths; -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.intToBytes; -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.pathExists; -import static org.apache.distributedlog.metadata.LogMetadata.ALLOCATION_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.LAYOUT_VERSION; -import static org.apache.distributedlog.metadata.LogMetadata.LOCK_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.LOGSEGMENTS_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.MAX_TXID_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.READ_LOCK_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.VERSION_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.getLogRootPath; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import java.net.URI; -import java.util.Collections; -import java.util.List; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.util.ZkUtils; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.DistributedLogConstants; -import org.apache.distributedlog.LogSegmentMetadata; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.apache.distributedlog.exceptions.LockingException; -import org.apache.distributedlog.exceptions.LogExistsException; -import org.apache.distributedlog.exceptions.LogNotFoundException; -import org.apache.distributedlog.exceptions.ZKException; -import org.apache.distributedlog.metadata.DLMetadata; -import org.apache.distributedlog.metadata.LogMetadata; -import org.apache.distributedlog.metadata.LogMetadataForWriter; -import org.apache.distributedlog.util.DLUtils; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.AsyncCallback.Children2Callback; -import org.apache.zookeeper.AsyncCallback.StatCallback; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.KeeperException.Code; -import org.apache.zookeeper.Transaction; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Test {@link ZKLogStreamMetadataStore}. - */ -public class TestZKLogStreamMetadataStore extends ZooKeeperClusterTestCase { - - private static final Logger logger = LoggerFactory.getLogger(TestZKLogStreamMetadataStore.class); - - private static final int sessionTimeoutMs = 30000; - - @Rule - public TestName testName = new TestName(); - - private ZooKeeperClient zkc; - private URI uri; - private OrderedScheduler scheduler; - private ZKLogStreamMetadataStore metadataStore; - - private static void createLog(ZooKeeperClient zk, URI uri, String logName, String logIdentifier) - throws Exception { - final String logRootPath = getLogRootPath(uri, logName, logIdentifier); - final String logSegmentsPath = logRootPath + LOGSEGMENTS_PATH; - final String maxTxIdPath = logRootPath + MAX_TXID_PATH; - final String lockPath = logRootPath + LOCK_PATH; - final String readLockPath = logRootPath + READ_LOCK_PATH; - final String versionPath = logRootPath + VERSION_PATH; - final String allocationPath = logRootPath + ALLOCATION_PATH; - - Utils.zkCreateFullPathOptimistic(zk, logRootPath, new byte[0], - zk.getDefaultACL(), CreateMode.PERSISTENT); - Transaction txn = zk.get().transaction(); - txn.create(logSegmentsPath, DLUtils.serializeLogSegmentSequenceNumber( - DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO), - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(maxTxIdPath, DLUtils.serializeTransactionId(0L), - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(lockPath, EMPTY_BYTES, - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(readLockPath, EMPTY_BYTES, - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(versionPath, intToBytes(LAYOUT_VERSION), - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(allocationPath, EMPTY_BYTES, - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.commit(); - } - - private static void createLog(ZooKeeperClient zk, - URI uri, - String logName, - String logIdentifier, - int numSegments) - throws Exception { - final String logRootPath = getLogRootPath(uri, logName, logIdentifier); - final String logSegmentsPath = logRootPath + LOGSEGMENTS_PATH; - final String maxTxIdPath = logRootPath + MAX_TXID_PATH; - final String lockPath = logRootPath + LOCK_PATH; - final String readLockPath = logRootPath + READ_LOCK_PATH; - final String versionPath = logRootPath + VERSION_PATH; - final String allocationPath = logRootPath + ALLOCATION_PATH; - - Utils.zkCreateFullPathOptimistic(zk, logRootPath, new byte[0], - zk.getDefaultACL(), CreateMode.PERSISTENT); - Transaction txn = zk.get().transaction(); - txn.create(logSegmentsPath, DLUtils.serializeLogSegmentSequenceNumber( - DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO), - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(maxTxIdPath, DLUtils.serializeTransactionId(0L), - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(lockPath, EMPTY_BYTES, - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(readLockPath, EMPTY_BYTES, - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(versionPath, intToBytes(LAYOUT_VERSION), - zk.getDefaultACL(), CreateMode.PERSISTENT); - txn.create(allocationPath, EMPTY_BYTES, - zk.getDefaultACL(), CreateMode.PERSISTENT); - - for (int i = 0; i < numSegments; i++) { - LogSegmentMetadata segment = DLMTestUtil.completedLogSegment( - logSegmentsPath, - i + 1L, - 1L + i * 1000L, - (i + 1) * 1000L, - 1000, - i + 1L, - 999L, - 0L); - txn.create( - segment.getZkPath(), - segment.getFinalisedData().getBytes(UTF_8), - zk.getDefaultACL(), - CreateMode.PERSISTENT); - } - - txn.commit(); - } - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .name("zkc") - .uri(DLMTestUtil.createDLMURI(zkPort, "/")) - .sessionTimeoutMs(sessionTimeoutMs) - .build(); - uri = DLMTestUtil.createDLMURI(zkPort, ""); - try { - ZkUtils.createFullPathOptimistic( - zkc.get(), - uri.getPath(), - new byte[0], - ZooDefs.Ids.OPEN_ACL_UNSAFE, - CreateMode.PERSISTENT); - } catch (KeeperException.NodeExistsException nee) { - logger.debug("The namespace uri already exists."); - } - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduler") - .numThreads(1) - .build(); - metadataStore = new ZKLogStreamMetadataStore( - "test-logstream-metadata-store", - new DistributedLogConfiguration(), - zkc, - scheduler, - NullStatsLogger.INSTANCE); - } - - @After - public void teardown() throws Exception { - if (null != metadataStore) { - metadataStore.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - zkc.close(); - } - - @Test(timeout = 60000) - public void testCheckLogMetadataPathsWithAllocator() throws Exception { - String logRootPath = "/" + testName.getMethodName(); - List> metadatas = - Utils.ioResult(checkLogMetadataPaths( - zkc.get(), logRootPath, true)); - assertEquals("Should have 8 paths", - 8, metadatas.size()); - for (Versioned path : metadatas.subList(2, metadatas.size())) { - assertNull(path.getValue()); - assertNull(path.getVersion()); - } - } - - @Test(timeout = 60000) - public void testCheckLogMetadataPathsWithoutAllocator() throws Exception { - String logRootPath = "/" + testName.getMethodName(); - List> metadatas = - Utils.ioResult(checkLogMetadataPaths( - zkc.get(), logRootPath, false)); - assertEquals("Should have 7 paths", - 7, metadatas.size()); - for (Versioned path : metadatas.subList(2, metadatas.size())) { - assertNull(path.getValue()); - assertNull(path.getVersion()); - } - } - - private void testCreateLogMetadataWithMissingPaths(URI uri, - String logName, - String logIdentifier, - List pathsToDelete, - boolean ownAllocator, - boolean createLogFirst) - throws Exception { - if (createLogFirst) { - createLog(zkc, uri, logName, logIdentifier); - } - // delete a path - for (String path : pathsToDelete) { - zkc.get().delete(path, -1); - } - - LogMetadataForWriter logMetadata = - Utils.ioResult(getLog(uri, logName, logIdentifier, zkc, ownAllocator, true)); - - final String logRootPath = getLogRootPath(uri, logName, logIdentifier); - - List> metadatas = - Utils.ioResult(checkLogMetadataPaths(zkc.get(), logRootPath, ownAllocator)); - - if (ownAllocator) { - assertEquals("Should have 8 paths : ownAllocator = " + ownAllocator, - 8, metadatas.size()); - } else { - assertEquals("Should have 7 paths : ownAllocator = " + ownAllocator, - 7, metadatas.size()); - } - - for (Versioned metadata : metadatas) { - assertTrue(pathExists(metadata)); - assertTrue(((LongVersion) metadata.getVersion()).getLongVersion() >= 0L); - } - - Versioned logSegmentsData = logMetadata.getMaxLSSNData(); - - assertEquals(DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO, - DLUtils.deserializeLogSegmentSequenceNumber(logSegmentsData.getValue())); - - Versioned maxTxIdData = logMetadata.getMaxTxIdData(); - - assertEquals(0L, DLUtils.deserializeTransactionId(maxTxIdData.getValue())); - - if (ownAllocator) { - Versioned allocationData = logMetadata.getAllocationData(); - assertEquals(0, allocationData.getValue().length); - } - } - - @Test(timeout = 60000) - public void testCreateLogMetadataMissingLogSegmentsPath() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - List pathsToDelete = Lists.newArrayList( - logRootPath + LOGSEGMENTS_PATH); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, false, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadataMissingMaxTxIdPath() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - List pathsToDelete = Lists.newArrayList( - logRootPath + MAX_TXID_PATH); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, false, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadataMissingLockPath() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - List pathsToDelete = Lists.newArrayList( - logRootPath + LOCK_PATH); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, false, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadataMissingReadLockPath() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - List pathsToDelete = Lists.newArrayList( - logRootPath + READ_LOCK_PATH); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, false, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadataMissingVersionPath() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - List pathsToDelete = Lists.newArrayList( - logRootPath + VERSION_PATH); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, false, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadataMissingAllocatorPath() throws Exception { - URI uri = DLMTestUtil.createDLMURI(zkPort, ""); - String logName = testName.getMethodName(); - String logIdentifier = ""; - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - List pathsToDelete = Lists.newArrayList( - logRootPath + ALLOCATION_PATH); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, true, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadataMissingAllPath() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - List pathsToDelete = Lists.newArrayList( - logRootPath + LOGSEGMENTS_PATH, - logRootPath + MAX_TXID_PATH, - logRootPath + LOCK_PATH, - logRootPath + READ_LOCK_PATH, - logRootPath + VERSION_PATH, - logRootPath + ALLOCATION_PATH); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, true, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadataOnExistedLog() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - List pathsToDelete = Lists.newArrayList(); - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, true, true); - } - - @Test(timeout = 60000) - public void testCreateLogMetadata() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - List pathsToDelete = Lists.newArrayList(); - - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, true, false); - } - - @Test(timeout = 60000, expected = LogNotFoundException.class) - public void testCreateLogMetadataWithCreateIfNotExistsSetToFalse() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - Utils.ioResult(getLog(uri, logName, logIdentifier, zkc, true, false)); - } - - @SuppressWarnings("deprecation") - @Test(timeout = 60000) - public void testCreateLogMetadataWithCustomMetadata() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - List pathsToDelete = Lists.newArrayList(); - - DLMetadata.create(new BKDLConfig(zkServers, "/ledgers")).update(uri); - - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(uri) - .build(); - - org.apache.distributedlog.api.MetadataAccessor accessor = - namespace.getNamespaceDriver().getMetadataAccessor(logName); - accessor.createOrUpdateMetadata(logName.getBytes("UTF-8")); - accessor.close(); - - testCreateLogMetadataWithMissingPaths(uri, logName, logIdentifier, pathsToDelete, true, false); - } - - @Test(timeout = 60000, expected = LogNotFoundException.class) - public void testGetLogSegmentsLogNotFound() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - - String logSegmentsPath = LogMetadata.getLogSegmentsPath(uri, logName, logIdentifier); - FutureUtils.result(getLogSegments(zkc, logSegmentsPath)); - } - - @Test(timeout = 60000) - public void testGetLogSegmentsZKExceptions() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - - ZooKeeper mockZk = mock(ZooKeeper.class); - ZooKeeperClient mockZkc = mock(ZooKeeperClient.class); - when(mockZkc.get()).thenReturn(mockZk); - doAnswer(invocationOnMock -> { - String path = (String) invocationOnMock.getArguments()[0]; - Children2Callback callback = (Children2Callback) invocationOnMock.getArguments()[2]; - callback.processResult(Code.BADVERSION.intValue(), path, null, null, null); - return null; - }).when(mockZk).getChildren(anyString(), anyBoolean(), any(Children2Callback.class), any()); - - String logSegmentsPath = LogMetadata.getLogSegmentsPath(uri, logName, logIdentifier); - try { - FutureUtils.result(getLogSegments(mockZkc, logSegmentsPath)); - fail("Should fail to get log segments when encountering zk exceptions"); - } catch (ZKException zke) { - assertEquals(Code.BADVERSION, zke.getKeeperExceptionCode()); - } - } - - @Test(timeout = 60000) - public void testGetLogSegments() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - - // create log - createLog( - zkc, - uri, - logName, - logIdentifier, - 5); - - List segments = FutureUtils.result( - getLogSegments(zkc, LogMetadata.getLogSegmentsPath(uri, logName, logIdentifier))); - assertEquals(5, segments.size()); - for (int i = 0; i < 5; i++) { - assertEquals(1L + i, segments.get(i).getLogSegmentSequenceNumber()); - } - } - - @Test(timeout = 60000) - public void testGetMissingPathsRecursive() throws Exception { - List missingPaths = FutureUtils.result( - getMissingPaths(zkc, uri, "path_missing/to/log")); - - assertEquals( - Lists.newArrayList( - uri.getPath() + "/path_missing/to/log", - uri.getPath() + "/path_missing/to", - uri.getPath() + "/path_missing" - ), - missingPaths); - } - - @Test(timeout = 60000) - public void testGetMissingPathsRecursive2() throws Exception { - String path = uri.getPath() + "/path_missing2/to/log"; - ZkUtils.createFullPathOptimistic( - zkc.get(), path, EMPTY_BYTES, zkc.getDefaultACL(), CreateMode.PERSISTENT); - - List missingPaths = FutureUtils.result( - getMissingPaths(zkc, uri, "path_missing2/to/log")); - - assertEquals( - Collections.emptyList(), - missingPaths); - } - - @Test(timeout = 60000) - public void testGetMissingPathsFailure() throws Exception { - ZooKeeper mockZk = mock(ZooKeeper.class); - ZooKeeperClient mockZkc = mock(ZooKeeperClient.class); - when(mockZkc.get()).thenReturn(mockZk); - doAnswer(invocationOnMock -> { - String path = (String) invocationOnMock.getArguments()[0]; - StatCallback callback = (StatCallback) invocationOnMock.getArguments()[2]; - callback.processResult(Code.BADVERSION.intValue(), path, null, null); - return null; - }).when(mockZk).exists(anyString(), anyBoolean(), any(StatCallback.class), any()); - - try { - FutureUtils.result(getMissingPaths(mockZkc, uri, "path_failure/to/log_failure")); - fail("Should fail on getting missing paths on zookeeper exceptions."); - } catch (ZKException zke) { - assertEquals(Code.BADVERSION, zke.getKeeperExceptionCode()); - } - } - - @Test(timeout = 60000) - public void testRenameLog() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - int numSegments = 5; - - createLog( - zkc, - uri, - logName, - logIdentifier, - numSegments); - - String newLogName = "path_rename/to/new/" + logName; - FutureUtils.result(metadataStore.renameLog(uri, logName, newLogName)); - } - - @Test(timeout = 60000, expected = LogExistsException.class) - public void testRenameLogExists() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - int numSegments = 5; - createLog( - zkc, - uri, - logName, - logIdentifier, - numSegments); - - String newLogName = "path_rename_exists/to/new/" + logName; - createLog( - zkc, - uri, - newLogName, - logIdentifier, - 3); - - FutureUtils.result(metadataStore.renameLog(uri, logName, newLogName)); - } - - @Test(timeout = 60000, expected = LockingException.class) - public void testRenameLockedLog() throws Exception { - String logName = testName.getMethodName(); - String logIdentifier = ""; - int numSegments = 5; - createLog( - zkc, - uri, - logName, - logIdentifier, - numSegments); - - // create a lock - String logRootPath = getLogRootPath(uri, logName, logIdentifier); - String lockPath = logRootPath + LOCK_PATH; - zkc.get().create(lockPath + "/test", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); - - String newLogName = "path_rename_locked/to/new/" + logName; - FutureUtils.result(metadataStore.renameLog(uri, logName, newLogName)); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStoreUtils.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStoreUtils.java deleted file mode 100644 index cc53775572b..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZKLogStreamMetadataStoreUtils.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl.metadata; - -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.intToBytes; -import static org.apache.distributedlog.impl.metadata.ZKLogStreamMetadataStore.processLogMetadatas; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.net.URI; -import java.util.List; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.exceptions.UnexpectedException; -import org.apache.distributedlog.metadata.LogMetadata; -import org.apache.distributedlog.metadata.LogMetadataForWriter; -import org.apache.distributedlog.util.DLUtils; -import org.junit.Test; - -/** - * TestZKLogStreamMetadataStoreUtils. - */ -public class TestZKLogStreamMetadataStoreUtils { - - @SuppressWarnings("unchecked") - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testProcessLogMetadatasMissingMaxTxnId() throws Exception { - String rootPath = "/test-missing-max-txn-id"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - new Versioned(null, null)); - processLogMetadatas(uri, logName, logIdentifier, metadatas, false); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testProcessLogMetadatasMissingVersion() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)), - new Versioned(null, null)); - processLogMetadatas(uri, logName, logIdentifier, metadatas, false); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testProcessLogMetadatasWrongVersion() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)), - new Versioned(intToBytes(9999), null)); - processLogMetadatas(uri, logName, logIdentifier, metadatas, false); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testProcessLogMetadatasMissingLockPath() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)), - new Versioned(intToBytes(LogMetadata.LAYOUT_VERSION), null), - new Versioned(null, null)); - processLogMetadatas(uri, logName, logIdentifier, metadatas, false); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testProcessLogMetadatasMissingReadLockPath() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)), - new Versioned(intToBytes(LogMetadata.LAYOUT_VERSION), null), - new Versioned(new byte[0], new LongVersion(1)), - new Versioned(null, null)); - processLogMetadatas(uri, logName, logIdentifier, metadatas, false); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testProcessLogMetadatasMissingLogSegmentsPath() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)), - new Versioned(intToBytes(LogMetadata.LAYOUT_VERSION), null), - new Versioned(new byte[0], new LongVersion(1)), - new Versioned(new byte[0], new LongVersion(1)), - new Versioned(null, null)); - processLogMetadatas(uri, logName, logIdentifier, metadatas, false); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testProcessLogMetadatasMissingAllocatorPath() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)), - new Versioned(intToBytes(LogMetadata.LAYOUT_VERSION), null), - new Versioned(new byte[0], new LongVersion(1)), - new Versioned(new byte[0], new LongVersion(1)), - new Versioned(DLUtils.serializeLogSegmentSequenceNumber(1L), new LongVersion(1)), - new Versioned(null, null)); - processLogMetadatas(uri, logName, logIdentifier, metadatas, true); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000) - public void testProcessLogMetadatasNoAllocatorPath() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - Versioned maxTxnIdData = - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)); - Versioned logSegmentsData = - new Versioned(DLUtils.serializeLogSegmentSequenceNumber(1L), new LongVersion(1)); - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - maxTxnIdData, - new Versioned(intToBytes(LogMetadata.LAYOUT_VERSION), null), - new Versioned(new byte[0], new LongVersion(1)), - new Versioned(new byte[0], new LongVersion(1)), - logSegmentsData); - LogMetadataForWriter metadata = - processLogMetadatas(uri, logName, logIdentifier, metadatas, false); - assertTrue(maxTxnIdData == metadata.getMaxTxIdData()); - assertTrue(logSegmentsData == metadata.getMaxLSSNData()); - assertNull(metadata.getAllocationData().getValue()); - assertNull(metadata.getAllocationData().getVersion()); - } - - @SuppressWarnings("unchecked") - @Test(timeout = 60000) - public void testProcessLogMetadatasAllocatorPath() throws Exception { - String rootPath = "/test-missing-version"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - Versioned maxTxnIdData = - new Versioned(DLUtils.serializeTransactionId(1L), new LongVersion(1)); - Versioned logSegmentsData = - new Versioned(DLUtils.serializeLogSegmentSequenceNumber(1L), new LongVersion(1)); - Versioned allocationData = - new Versioned(DLUtils.logSegmentId2Bytes(1L), new LongVersion(1)); - List> metadatas = Lists.newArrayList( - new Versioned(null, null), - new Versioned(null, null), - maxTxnIdData, - new Versioned(intToBytes(LogMetadata.LAYOUT_VERSION), null), - new Versioned(new byte[0], new LongVersion(1)), - new Versioned(new byte[0], new LongVersion(1)), - logSegmentsData, - allocationData); - LogMetadataForWriter metadata = - processLogMetadatas(uri, logName, logIdentifier, metadatas, true); - assertTrue(maxTxnIdData == metadata.getMaxTxIdData()); - assertTrue(logSegmentsData == metadata.getMaxLSSNData()); - assertTrue(allocationData == metadata.getAllocationData()); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZkMetadataResolver.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZkMetadataResolver.java deleted file mode 100644 index 944ce98815c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/impl/metadata/TestZkMetadataResolver.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.impl.metadata; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.DistributedLogConstants; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.distributedlog.metadata.DLMetadata; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - - - - - - -/** - * TestZkMetadataResolver. - */ -public class TestZkMetadataResolver extends ZooKeeperClusterTestCase { - - private static final BKDLConfig bkdlConfig = new BKDLConfig("127.0.0.1:7000", "ledgers"); - private static final BKDLConfig bkdlConfig2 = new BKDLConfig("127.0.0.1:7000", "ledgers2"); - - private ZooKeeperClient zkc; - private ZkMetadataResolver resolver; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createURI("/")) - .sessionTimeoutMs(10000) - .build(); - resolver = new ZkMetadataResolver(zkc); - } - - @After - public void tearDown() throws Exception { - zkc.close(); - } - - private URI createURI(String path) { - return URI.create("distributedlog://127.0.0.1:" + zkPort + path); - } - - @Test(timeout = 60000) - public void testResolveFailures() throws Exception { - // resolve unexisted path - try { - resolver.resolve(createURI("/unexisted/path")); - fail("Should fail if no metadata resolved."); - } catch (IOException e) { - // expected - } - // resolve existed unbound path - Utils.zkCreateFullPathOptimistic(zkc, "/existed/path", new byte[0], - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - try { - resolver.resolve(createURI("/existed/path")); - fail("Should fail if no metadata resolved."); - } catch (IOException e) { - // expected - } - } - - @Test(timeout = 60000) - public void testResolve() throws Exception { - DLMetadata dlMetadata = DLMetadata.create(bkdlConfig); - dlMetadata.create(createURI("/messaging/distributedlog-testresolve")); - DLMetadata dlMetadata2 = DLMetadata.create(bkdlConfig2); - dlMetadata2.create(createURI("/messaging/distributedlog-testresolve/child")); - assertEquals(dlMetadata, - resolver.resolve(createURI("/messaging/distributedlog-testresolve"))); - assertEquals(dlMetadata2, - resolver.resolve(createURI("/messaging/distributedlog-testresolve/child"))); - assertEquals(dlMetadata2, - resolver.resolve(createURI("/messaging/distributedlog-testresolve/child/unknown"))); - Utils.zkCreateFullPathOptimistic(zkc, "/messaging/distributedlog-testresolve/child/child2", new byte[0], - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - assertEquals(dlMetadata2, - resolver.resolve(createURI("/messaging/distributedlog-testresolve/child/child2"))); - } - - @Test(timeout = 60000) - public void testEncodeRegionID() throws Exception { - DistributedLogConfiguration dlConf = new DistributedLogConfiguration(); - - URI uri = createURI("/messaging/distributedlog-testencoderegionid/dl1"); - DLMetadata meta1 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers")); - meta1.create(uri); - BKDLConfig read1 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read1, dlConf); - assertFalse(dlConf.getEncodeRegionIDInLogSegmentMetadata()); - - BKDLConfig.clearCachedDLConfigs(); - - DLMetadata meta2 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers").setEncodeRegionID(true)); - meta2.update(uri); - BKDLConfig read2 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read2, dlConf); - assertTrue(dlConf.getEncodeRegionIDInLogSegmentMetadata()); - - BKDLConfig.clearCachedDLConfigs(); - - DLMetadata meta3 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers").setEncodeRegionID(false)); - meta3.update(uri); - BKDLConfig read3 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read3, dlConf); - assertFalse(dlConf.getEncodeRegionIDInLogSegmentMetadata()); - - BKDLConfig.clearCachedDLConfigs(); - } - - @Test(timeout = 60000) - public void testFirstLogSegmentSequenceNumber() throws Exception { - DistributedLogConfiguration dlConf = new DistributedLogConfiguration(); - - URI uri = createURI("/messaging/distributedlog-testfirstledgerseqno/dl1"); - DLMetadata meta1 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers")); - meta1.create(uri); - BKDLConfig read1 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read1, dlConf); - assertEquals(DistributedLogConstants.FIRST_LOGSEGMENT_SEQNO, dlConf.getFirstLogSegmentSequenceNumber()); - - BKDLConfig.clearCachedDLConfigs(); - - DLMetadata meta2 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers") - .setFirstLogSegmentSeqNo(9999L)); - meta2.update(uri); - BKDLConfig read2 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read2, dlConf); - assertEquals(9999L, dlConf.getFirstLogSegmentSequenceNumber()); - - BKDLConfig.clearCachedDLConfigs(); - - DLMetadata meta3 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers") - .setFirstLogSegmentSeqNo(99L)); - meta3.update(uri); - BKDLConfig read3 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read3, dlConf); - assertEquals(99L, dlConf.getFirstLogSegmentSequenceNumber()); - - BKDLConfig.clearCachedDLConfigs(); - } - - @Test(timeout = 60000) - public void testFederatedNamespace() throws Exception { - DistributedLogConfiguration dlConf = new DistributedLogConfiguration(); - - URI uri = createURI("/messaging/distributedlog-testfederatednamespace/dl1"); - DLMetadata meta1 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers")); - meta1.create(uri); - BKDLConfig read1 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read1, dlConf); - assertTrue(dlConf.getCreateStreamIfNotExists()); - - BKDLConfig.clearCachedDLConfigs(); - - DLMetadata meta2 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers") - .setFederatedNamespace(true)); - meta2.update(uri); - BKDLConfig read2 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read2, dlConf); - assertFalse(dlConf.getCreateStreamIfNotExists()); - - BKDLConfig.clearCachedDLConfigs(); - - DLMetadata meta3 = DLMetadata.create(new BKDLConfig("127.0.0.1:7000", "ledgers") - .setFederatedNamespace(false)); - meta3.update(uri); - BKDLConfig read3 = BKDLConfig.resolveDLConfig(zkc, uri); - BKDLConfig.propagateConfiguration(read3, dlConf); - // if it is non-federated namespace, it won't change the create stream behavior. - assertFalse(dlConf.getCreateStreamIfNotExists()); - - BKDLConfig.clearCachedDLConfigs(); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/limiter/TestRequestLimiter.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/limiter/TestRequestLimiter.java deleted file mode 100644 index 07eae94a4d2..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/limiter/TestRequestLimiter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.limiter; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - - - -/** - * TestRequestLimiter. - */ -public class TestRequestLimiter { - - class MockRequest { - } - - class MockRequestLimiter implements RequestLimiter { - int count; - MockRequestLimiter() { - this.count = 0; - } - public void apply(MockRequest request) { - count++; - } - public int getCount() { - return count; - } - } - - @Test(timeout = 60000) - public void testChainedRequestLimiter() throws Exception { - MockRequestLimiter limiter1 = new MockRequestLimiter(); - MockRequestLimiter limiter2 = new MockRequestLimiter(); - ChainedRequestLimiter.Builder limiterBuilder = - new ChainedRequestLimiter.Builder(); - limiterBuilder.addLimiter(limiter1) - .addLimiter(limiter2); - ChainedRequestLimiter limiter = limiterBuilder.build(); - assertEquals(0, limiter1.getCount()); - assertEquals(0, limiter2.getCount()); - limiter.apply(new MockRequest()); - assertEquals(1, limiter1.getCount()); - assertEquals(1, limiter2.getCount()); - limiter.apply(new MockRequest()); - assertEquals(2, limiter1.getCount()); - assertEquals(2, limiter2.getCount()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestDistributedLock.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestDistributedLock.java deleted file mode 100644 index 43e9aca052f..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestDistributedLock.java +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.lock; - -import static org.apache.distributedlog.lock.ZKSessionLock.asyncParseClientID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.common.concurrent.FutureEventListener; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClientUtils; -import org.apache.distributedlog.exceptions.LockingException; -import org.apache.distributedlog.exceptions.OwnershipAcquireFailedException; -import org.apache.distributedlog.exceptions.UnexpectedException; -import org.apache.distributedlog.util.FailpointUtils; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Distributed Lock Tests. - */ -public class TestDistributedLock extends TestDistributedLogBase { - - private static final Logger logger = LoggerFactory.getLogger(TestDistributedLock.class); - - @Rule - public TestName runtime = new TestName(); - - private static final int sessionTimeoutMs = 2000; - - private ZooKeeperClient zkc; - private ZooKeeperClient zkc0; // used for checking - private OrderedScheduler lockStateExecutor; - - @Before - public void setup() throws Exception { - zkc = ZooKeeperClientBuilder.newBuilder() - .name("zkc") - .uri(createDLMURI("/")) - .sessionTimeoutMs(sessionTimeoutMs) - .zkAclId(null) - .build(); - zkc0 = ZooKeeperClientBuilder.newBuilder() - .name("zkc0") - .uri(createDLMURI("/")) - .sessionTimeoutMs(sessionTimeoutMs) - .zkAclId(null) - .build(); - lockStateExecutor = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduer") - .numThreads(1) - .build(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - zkc0.close(); - lockStateExecutor.shutdown(); - } - - private static void createLockPath(ZooKeeper zk, String lockPath) throws Exception { - zk.create(lockPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } - - private static List getLockWaiters(ZooKeeperClient zkc, String lockPath) throws Exception { - List children = zkc.get().getChildren(lockPath, false); - Collections.sort(children, ZKSessionLock.MEMBER_COMPARATOR); - return children; - } - - static class TestLockFactory { - final String lockPath; - final String clientId; - final OrderedScheduler lockStateExecutor; - - public TestLockFactory(String name, - ZooKeeperClient defaultZkc, - OrderedScheduler lockStateExecutor) - throws Exception { - this.lockPath = "/" + name + System.currentTimeMillis(); - this.clientId = name; - createLockPath(defaultZkc.get(), lockPath); - this.lockStateExecutor = lockStateExecutor; - - } - public ZKDistributedLock createLock(int id, ZooKeeperClient zkc) throws Exception { - SessionLockFactory lockFactory = new ZKSessionLockFactory( - zkc, - clientId + id, - lockStateExecutor, - 0, - Long.MAX_VALUE, - sessionTimeoutMs, - NullStatsLogger.INSTANCE); - return new ZKDistributedLock( - this.lockStateExecutor, - lockFactory, - this.lockPath, - Long.MAX_VALUE, - NullStatsLogger.INSTANCE); - } - public String getLockPath() { - return lockPath; - } - } - - static class CountDownThrowFailPointAction extends FailpointUtils.AbstractFailPointAction { - - final AtomicInteger successCounter; - final AtomicInteger failureCounter; - - CountDownThrowFailPointAction(int successCount, int failureCount) { - this.successCounter = new AtomicInteger(successCount); - this.failureCounter = new AtomicInteger(failureCount); - } - - @Override - public boolean checkFailPoint() throws IOException { - int successCount = successCounter.getAndDecrement(); - if (successCount > 0) { - return true; - } - int count = failureCounter.getAndDecrement(); - if (count > 0) { - throw new IOException("counter = " + count); - } - return true; - } - } - - private SessionLockFactory createLockFactory(String clientId, - ZooKeeperClient zkc) { - return createLockFactory(clientId, zkc, Long.MAX_VALUE, 0); - } - private SessionLockFactory createLockFactory(String clientId, - ZooKeeperClient zkc, - long lockTimeoutMs, - int recreationTimes) { - return new ZKSessionLockFactory( - zkc, - clientId, - lockStateExecutor, - recreationTimes, - lockTimeoutMs, - sessionTimeoutMs, - NullStatsLogger.INSTANCE); - } - - private static void checkLockAndReacquire(ZKDistributedLock lock, boolean sync) throws Exception { - lock.checkOwnershipAndReacquire(); - CompletableFuture reacquireFuture = lock.getLockReacquireFuture(); - if (null != reacquireFuture && sync) { - Utils.ioResult(reacquireFuture); - } - } - - @Test(timeout = 60000) - public void testZooKeeperConnectionLossOnLockCreation() throws Exception { - String lockPath = "/test-zookeeper-connection-loss-on-lock-creation-" + System.currentTimeMillis(); - String clientId = "zookeeper-connection-loss"; - - createLockPath(zkc.get(), lockPath); - - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_ZooKeeperConnectionLoss, - new CountDownThrowFailPointAction(0, Integer.MAX_VALUE)); - SessionLockFactory lockFactory = createLockFactory(clientId, zkc, Long.MAX_VALUE, 0); - try { - try { - ZKDistributedLock lock = new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock.asyncAcquire()); - fail("Should fail on creating lock if couldn't establishing connections to zookeeper"); - } catch (IOException ioe) { - // expected. - } - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_ZooKeeperConnectionLoss); - } - - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_ZooKeeperConnectionLoss, - new CountDownThrowFailPointAction(0, Integer.MAX_VALUE)); - lockFactory = createLockFactory(clientId, zkc, Long.MAX_VALUE, 3); - try { - try { - ZKDistributedLock lock = new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock.asyncAcquire()); - fail("Should fail on creating lock if couldn't establishing connections to zookeeper after 3 retries"); - } catch (IOException ioe) { - // expected. - } - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_ZooKeeperConnectionLoss); - } - - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_ZooKeeperConnectionLoss, - new CountDownThrowFailPointAction(0, 3)); - lockFactory = createLockFactory(clientId, zkc, Long.MAX_VALUE, 5); - try { - ZKDistributedLock lock = new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock.asyncAcquire()); - - Pair lockId1 = ((ZKSessionLock) lock.getInternalLock()).getLockId(); - - List children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertTrue(lock.haveLock()); - assertEquals(lockId1, Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - lock.asyncClose(); - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_ZooKeeperConnectionLoss); - } - } - - @Test(timeout = 60000) - public void testBasicAcquireRelease() throws Exception { - String lockPath = "/test-basic-acquire-release-" + System.currentTimeMillis(); - String clientId = "basic-acquire-release"; - - createLockPath(zkc.get(), lockPath); - - SessionLockFactory lockFactory = createLockFactory(clientId, zkc); - ZKDistributedLock lock = new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock.asyncAcquire()); - - Pair lockId1 = ((ZKSessionLock) lock.getInternalLock()).getLockId(); - - List children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertTrue(lock.haveLock()); - assertEquals(lockId1, Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - Utils.ioResult(lock.asyncClose()); - - children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - assertFalse(lock.haveLock()); - - lock = new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock.asyncAcquire()); - - Pair lockId2 = ((ZKSessionLock) lock.getInternalLock()).getLockId(); - - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertTrue(lock.haveLock()); - assertEquals(lockId2, Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - assertEquals(lockId1, lockId2); - - Utils.ioResult(lock.asyncClose()); - - children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - assertFalse(lock.haveLock()); - - try { - Utils.ioResult(lock.asyncAcquire()); - fail("Should fail on acquiring a closed lock"); - } catch (UnexpectedException le) { - // expected. - } - children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - assertFalse(lock.haveLock()); - } - - @Test(timeout = 60000) - public void testCheckWriteLockFailureWhenLockIsAcquiredByOthers() throws Exception { - String lockPath = "/test-check-write-lock-failure-when-lock-is-acquired-by-others-" - + System.currentTimeMillis(); - String clientId = "test-check-write-lock-failure"; - - createLockPath(zkc.get(), lockPath); - - SessionLockFactory lockFactory0 = createLockFactory(clientId, zkc0); - ZKDistributedLock lock0 = - new ZKDistributedLock(lockStateExecutor, lockFactory0, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock0.asyncAcquire()); - - Pair lockId0_1 = ((ZKSessionLock) lock0.getInternalLock()).getLockId(); - - List children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertTrue(lock0.haveLock()); - assertEquals(lockId0_1, - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - // expire the session - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - - // reacquire the lock and wait reacquire completed - checkLockAndReacquire(lock0, true); - - Pair lockId0_2 = ((ZKSessionLock) lock0.getInternalLock()).getLockId(); - assertFalse("New lock should be created under different session", lockId0_1.equals(lockId0_2)); - - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertTrue(lock0.haveLock()); - assertEquals(lockId0_2, - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - - SessionLockFactory lockFactory = createLockFactory(clientId, zkc); - final ZKDistributedLock lock1 = - new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - final CountDownLatch lockLatch = new CountDownLatch(1); - Thread lockThread = new Thread(new Runnable() { - @Override - public void run() { - try { - Utils.ioResult(lock1.asyncAcquire()); - lockLatch.countDown(); - } catch (Exception e) { - logger.error("Failed on locking lock1 : ", e); - } - } - }, "lock-thread"); - lockThread.start(); - - // ensure lock1 is waiting for lock0 - do { - Thread.sleep(1); - children = getLockWaiters(zkc, lockPath); - } while (children.size() < 2); - - // expire the session - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - - lockLatch.await(); - lockThread.join(); - - try { - checkLockAndReacquire(lock0, true); - fail("Should fail on checking write lock since lock is acquired by lock1"); - } catch (LockingException le) { - // expected - } - - try { - checkLockAndReacquire(lock0, false); - fail("Should fail on checking write lock since lock is acquired by lock1"); - } catch (LockingException le) { - // expected - } - } - - /** - * If no lock is acquired between session expired and re-acquisition, check write lock will acquire the lock. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockReacquireSuccessAfterCheckWriteLock() throws Exception { - testLockReacquireSuccess(true); - } - - /** - * If no lock is acquired between session expired and re-acquisition, check write lock will acquire the lock. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockReacquireSuccessWithoutCheckWriteLock() throws Exception { - testLockReacquireSuccess(false); - } - - private void testLockReacquireSuccess(boolean checkOwnershipAndReacquire) throws Exception { - String lockPath = "/test-lock-re-acquire-success-" + checkOwnershipAndReacquire - + "-" + System.currentTimeMillis(); - String clientId = "test-lock-re-acquire"; - - createLockPath(zkc.get(), lockPath); - - SessionLockFactory lockFactory0 = createLockFactory(clientId, zkc0); - ZKDistributedLock lock0 = - new ZKDistributedLock(lockStateExecutor, lockFactory0, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock0.asyncAcquire()); - - Pair lockId0_1 = ((ZKSessionLock) lock0.getInternalLock()).getLockId(); - - List children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertTrue(lock0.haveLock()); - assertEquals(lockId0_1, - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - - if (checkOwnershipAndReacquire) { - checkLockAndReacquire(lock0, true); - checkLockAndReacquire(lock0, false); - } else { - // session expire will trigger lock re-acquisition - CompletableFuture asyncLockAcquireFuture; - do { - Thread.sleep(1); - asyncLockAcquireFuture = lock0.getLockReacquireFuture(); - } while (null == asyncLockAcquireFuture && lock0.getReacquireCount() < 1); - if (null != asyncLockAcquireFuture) { - Utils.ioResult(asyncLockAcquireFuture); - } - checkLockAndReacquire(lock0, false); - } - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertTrue(lock0.haveLock()); - Pair lock0_2 = ((ZKSessionLock) lock0.getInternalLock()).getLockId(); - assertEquals(lock0_2, - Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - assertEquals(clientId, lock0_2.getLeft()); - assertFalse(lockId0_1.equals(lock0_2)); - - Utils.ioResult(lock0.asyncClose()); - - children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - } - - /** - * If lock is acquired between session expired and re-acquisition, check write lock will be failed. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockReacquireFailureAfterCheckWriteLock() throws Exception { - testLockReacquireFailure(true); - } - - /** - * If lock is acquired between session expired and re-acquisition, check write lock will be failed. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockReacquireFailureWithoutCheckWriteLock() throws Exception { - testLockReacquireFailure(false); - } - - private void testLockReacquireFailure(boolean checkOwnershipAndReacquire) throws Exception { - String lockPath = "/test-lock-re-acquire-failure-" + checkOwnershipAndReacquire - + "-" + System.currentTimeMillis(); - String clientId = "test-lock-re-acquire"; - - createLockPath(zkc.get(), lockPath); - - SessionLockFactory lockFactory0 = createLockFactory(clientId, zkc0); - ZKDistributedLock lock0 = - new ZKDistributedLock(lockStateExecutor, lockFactory0, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Utils.ioResult(lock0.asyncAcquire()); - - final CountDownLatch lock1DoneLatch = new CountDownLatch(1); - SessionLockFactory lockFactory1 = createLockFactory(clientId, zkc); - final ZKDistributedLock lock1 = - new ZKDistributedLock(lockStateExecutor, lockFactory1, lockPath, - Long.MAX_VALUE, NullStatsLogger.INSTANCE); - Thread lock1Thread = new Thread(new Runnable() { - @Override - public void run() { - try { - Utils.ioResult(lock1.asyncAcquire()); - lock1DoneLatch.countDown(); - } catch (Exception e) { - logger.error("Error on acquiring lock1 : ", e); - } - } - }, "lock1-thread"); - lock1Thread.start(); - - List children; - do { - Thread.sleep(1); - children = getLockWaiters(zkc, lockPath); - } while (children.size() < 2); - assertEquals(2, children.size()); - assertTrue(lock0.haveLock()); - assertFalse(lock1.haveLock()); - assertEquals(((ZKSessionLock) lock0.getInternalLock()).getLockId(), - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - assertEquals(((ZKSessionLock) lock1.getInternalLock()).getLockId(), - Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(1)))); - - logger.info("Expiring session on lock0"); - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - logger.info("Session on lock0 is expired"); - lock1DoneLatch.await(); - assertFalse(lock0.haveLock()); - assertTrue(lock1.haveLock()); - - if (checkOwnershipAndReacquire) { - try { - checkLockAndReacquire(lock0, true); - fail("Should fail check write lock since lock is already held by other people"); - } catch (OwnershipAcquireFailedException oafe) { - assertEquals(((ZKSessionLock) lock1.getInternalLock()).getLockId().getLeft(), - oafe.getCurrentOwner()); - } - try { - checkLockAndReacquire(lock0, false); - fail("Should fail check write lock since lock is already held by other people"); - } catch (OwnershipAcquireFailedException oafe) { - assertEquals(((ZKSessionLock) lock1.getInternalLock()).getLockId().getLeft(), - oafe.getCurrentOwner()); - } - } else { - logger.info("Waiting lock0 to attempt acquisition after session expired"); - // session expire will trigger lock re-acquisition - CompletableFuture asyncLockAcquireFuture; - do { - Thread.sleep(1); - asyncLockAcquireFuture = lock0.getLockReacquireFuture(); - } while (null == asyncLockAcquireFuture); - - try { - Utils.ioResult(asyncLockAcquireFuture); - fail("Should fail check write lock since lock is already held by other people"); - } catch (OwnershipAcquireFailedException oafe) { - assertEquals(((ZKSessionLock) lock1.getInternalLock()).getLockId().getLeft(), - oafe.getCurrentOwner()); - } - try { - checkLockAndReacquire(lock0, false); - fail("Should fail check write lock since lock is already held by other people"); - } catch (OwnershipAcquireFailedException oafe) { - assertEquals(((ZKSessionLock) lock1.getInternalLock()).getLockId().getLeft(), - oafe.getCurrentOwner()); - } - } - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertFalse(lock0.haveLock()); - assertTrue(lock1.haveLock()); - assertEquals(((ZKSessionLock) lock1.getInternalLock()).getLockId(), - Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - - Utils.ioResult(lock0.asyncClose()); - Utils.ioResult(lock1.asyncClose()); - - children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - } - - @Test(timeout = 60000) - public void testLockReacquire() throws Exception { - String lockPath = "/reacquirePath"; - Utils.zkCreateFullPathOptimistic(zkc, lockPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, - CreateMode.PERSISTENT); - String clientId = "lockHolder"; - SessionLockFactory lockFactory = createLockFactory(clientId, zkc, conf.getLockTimeoutMilliSeconds(), 0); - ZKDistributedLock lock = new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - conf.getLockTimeoutMilliSeconds(), NullStatsLogger.INSTANCE); - Utils.ioResult(lock.asyncAcquire()); - - // try and cleanup the underlying lock - lock.getInternalLock().unlock(); - - // This should reacquire the lock - checkLockAndReacquire(lock, true); - - assertEquals(true, lock.haveLock()); - assertEquals(true, lock.getInternalLock().isLockHeld()); - - lockFactory = createLockFactory(clientId + "_2", zkc, conf.getLockTimeoutMilliSeconds(), 0); - ZKDistributedLock lock2 = new ZKDistributedLock(lockStateExecutor, lockFactory, lockPath, - 0, NullStatsLogger.INSTANCE); - - boolean exceptionEncountered = false; - try { - Utils.ioResult(lock2.asyncAcquire()); - } catch (OwnershipAcquireFailedException exc) { - assertEquals(clientId, exc.getCurrentOwner()); - exceptionEncountered = true; - } - assertTrue(exceptionEncountered); - Utils.ioResult(lock.asyncClose()); - Utils.ioResult(lock2.asyncClose()); - } - - @Test(timeout = 60000) - public void testLockReacquireMultiple() throws Exception { - String lockPath = "/reacquirePathMultiple"; - Utils.zkCreateFullPathOptimistic(zkc, lockPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, - CreateMode.PERSISTENT); - String clientId = "lockHolder"; - SessionLockFactory factory = createLockFactory(clientId, zkc, conf.getLockTimeoutMilliSeconds(), 0); - ZKDistributedLock lock = new ZKDistributedLock(lockStateExecutor, factory, lockPath, - conf.getLockTimeoutMilliSeconds(), NullStatsLogger.INSTANCE); - Utils.ioResult(lock.asyncAcquire()); - - // try and cleanup the underlying lock - lock.getInternalLock().unlock(); - - // This should reacquire the lock - checkLockAndReacquire(lock, true); - - assertEquals(true, lock.haveLock()); - assertEquals(true, lock.getInternalLock().isLockHeld()); - - factory = createLockFactory(clientId + "_2", zkc, 0, 0); - ZKDistributedLock lock2 = new ZKDistributedLock(lockStateExecutor, factory, lockPath, - 0, NullStatsLogger.INSTANCE); - - boolean exceptionEncountered = false; - try { - Utils.ioResult(lock2.asyncAcquire()); - } catch (OwnershipAcquireFailedException exc) { - assertEquals(clientId, exc.getCurrentOwner()); - exceptionEncountered = true; - } - assertTrue(exceptionEncountered); - Utils.ioResult(lock2.asyncClose()); - - Utils.ioResult(lock.asyncClose()); - assertEquals(false, lock.haveLock()); - assertEquals(false, lock.getInternalLock().isLockHeld()); - - factory = createLockFactory(clientId + "_3", zkc, 0, 0); - ZKDistributedLock lock3 = new ZKDistributedLock(lockStateExecutor, factory, lockPath, - 0, NullStatsLogger.INSTANCE); - - Utils.ioResult(lock3.asyncAcquire()); - assertEquals(true, lock3.haveLock()); - assertEquals(true, lock3.getInternalLock().isLockHeld()); - Utils.ioResult(lock3.asyncClose()); - } - - void assertLatchesSet(CountDownLatch[] latches, int endIndex) { - for (int i = 0; i < endIndex; i++) { - assertEquals("latch " + i + " should have been set", 0, latches[i].getCount()); - } - for (int i = endIndex; i < latches.length; i++) { - assertEquals("latch " + i + " should not have been set", 1, latches[i].getCount()); - } - } - - // Assert key lock state (is locked, is internal locked, lock count, etc.) for two dlocks. - void assertLockState(ZKDistributedLock lock0, boolean owned0, boolean intOwned0, - ZKDistributedLock lock1, boolean owned1, boolean intOwned1, - int waiters, String lockPath) throws Exception { - assertEquals(owned0, lock0.haveLock()); - assertEquals(intOwned0, lock0.getInternalLock() != null && lock0.getInternalLock().isLockHeld()); - assertEquals(owned1, lock1.haveLock()); - assertEquals(intOwned1, lock1.getInternalLock() != null && lock1.getInternalLock().isLockHeld()); - assertEquals(waiters, getLockWaiters(zkc, lockPath).size()); - } - - @Test(timeout = 60000) - public void testAsyncAcquireBasics() throws Exception { - TestLockFactory locks = new TestLockFactory(runtime.getMethodName(), zkc, lockStateExecutor); - - int count = 3; - ArrayList> results = - new ArrayList>(count); - ZKDistributedLock[] lockArray = new ZKDistributedLock[count]; - final CountDownLatch[] latches = new CountDownLatch[count]; - - // Set up waiters, save async results, count down a latch when lock is acquired in - // the future. - for (int i = 0; i < count; i++) { - latches[i] = new CountDownLatch(1); - lockArray[i] = locks.createLock(i, zkc); - final int index = i; - results.add(lockArray[i].asyncAcquire().whenComplete( - new FutureEventListener() { - @Override - public void onSuccess(ZKDistributedLock lock) { - latches[index].countDown(); - } - @Override - public void onFailure(Throwable cause) { - fail("unexpected failure " + cause); - } - } - )); - } - - // Now await ownership and release ownership of locks one by one (in the order they were - // acquired). - for (int i = 0; i < count; i++) { - latches[i].await(); - assertLatchesSet(latches, i + 1); - Utils.ioResult(results.get(i)); - Utils.ioResult(lockArray[i].asyncClose()); - } - } - - @Test(timeout = 60000) - public void testAsyncAcquireSyncThenAsyncOnSameLock() throws Exception { - TestLockFactory locks = new TestLockFactory(runtime.getMethodName(), zkc, lockStateExecutor); - final ZKDistributedLock lock0 = locks.createLock(0, zkc); - final ZKDistributedLock lock1 = locks.createLock(1, zkc0); - - Utils.ioResult(lock0.asyncAcquire()); - - // Initial state. - assertLockState(lock0, true, true, lock1, false, false, 1, locks.getLockPath()); - - Thread lock1Thread = new Thread(new Runnable() { - @Override - public void run() { - try { - Utils.ioResult(lock1.asyncAcquire()); - } catch (Exception e) { - fail("shouldn't fail to acquire"); - } - } - }, "lock1-thread"); - lock1Thread.start(); - - // Wait for lock count to increase, indicating background acquire has succeeded. - while (getLockWaiters(zkc, locks.getLockPath()).size() < 2) { - Thread.sleep(1); - } - assertLockState(lock0, true, true, lock1, false, false, 2, locks.getLockPath()); - - Utils.ioResult(lock0.asyncClose()); - Utils.ioResult(lock1.getLockAcquireFuture()); - - assertLockState(lock0, false, false, lock1, true, true, 1, locks.getLockPath()); - - // Release lock1 - Utils.ioResult(lock1.asyncClose()); - assertLockState(lock0, false, false, lock1, false, false, 0, locks.getLockPath()); - } - - @Test(timeout = 60000) - public void testAsyncAcquireExpireDuringWait() throws Exception { - TestLockFactory locks = new TestLockFactory(runtime.getMethodName(), zkc, lockStateExecutor); - final ZKDistributedLock lock0 = locks.createLock(0, zkc); - final ZKDistributedLock lock1 = locks.createLock(1, zkc0); - - Utils.ioResult(lock0.asyncAcquire()); - CompletableFuture result = lock1.asyncAcquire(); - // make sure we place a waiter for lock1 - while (null == lock1.getLockWaiter()) { - TimeUnit.MILLISECONDS.sleep(20); - } - - // Expire causes acquire future to be failed and unset. - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - try { - Utils.ioResult(result); - fail("future should have been failed"); - } catch (OwnershipAcquireFailedException ex) { - } - - assertLockState(lock0, true, true, lock1, false, false, 1, locks.getLockPath()); - lock0.asyncClose(); - lock1.asyncClose(); - } - - @Test(timeout = 60000) - public void testAsyncAcquireCloseDuringWait() throws Exception { - TestLockFactory locks = new TestLockFactory(runtime.getMethodName(), zkc, lockStateExecutor); - final ZKDistributedLock lock0 = locks.createLock(0, zkc); - final ZKDistributedLock lock1 = locks.createLock(1, zkc0); - - Utils.ioResult(lock0.asyncAcquire()); - CompletableFuture result = lock1.asyncAcquire(); - Utils.ioResult(lock1.asyncClose()); - try { - Utils.ioResult(result); - fail("future should have been failed"); - } catch (LockClosedException ex) { - } - - assertLockState(lock0, true, true, lock1, false, false, 1, locks.getLockPath()); - lock0.asyncClose(); - } - - @Test(timeout = 60000) - public void testAsyncAcquireCloseAfterAcquire() throws Exception { - TestLockFactory locks = new TestLockFactory(runtime.getMethodName(), zkc, lockStateExecutor); - final ZKDistributedLock lock0 = locks.createLock(0, zkc); - - CompletableFuture result = lock0.asyncAcquire(); - Utils.ioResult(result); - Utils.ioResult(lock0.asyncClose()); - - // Already have this, stays satisfied. - Utils.ioResult(result); - - // But we no longer have the lock. - assertEquals(false, lock0.haveLock()); - assertEquals(false, lock0.getInternalLock().isLockHeld()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestZKSessionLock.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestZKSessionLock.java deleted file mode 100644 index 9c05f6ef473..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/lock/TestZKSessionLock.java +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.lock; - -import static org.apache.distributedlog.lock.ZKSessionLock.areLockWaitersInSameSession; -import static org.apache.distributedlog.lock.ZKSessionLock.asyncParseClientID; -import static org.apache.distributedlog.lock.ZKSessionLock.getLockIdFromPath; -import static org.apache.distributedlog.lock.ZKSessionLock.getLockPathPrefixV1; -import static org.apache.distributedlog.lock.ZKSessionLock.getLockPathPrefixV2; -import static org.apache.distributedlog.lock.ZKSessionLock.getLockPathPrefixV3; -import static org.apache.distributedlog.lock.ZKSessionLock.parseMemberID; -import static org.apache.distributedlog.lock.ZKSessionLock.serializeClientId; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClientUtils; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.distributedlog.exceptions.LockingException; -import org.apache.distributedlog.exceptions.OwnershipAcquireFailedException; -import org.apache.distributedlog.lock.ZKSessionLock.State; -import org.apache.distributedlog.util.FailpointUtils; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.ZooDefs; -import org.apache.zookeeper.ZooKeeper; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Distributed Lock Tests. - */ -public class TestZKSessionLock extends ZooKeeperClusterTestCase { - - @Rule - public TestName testNames = new TestName(); - - private static final Logger logger = LoggerFactory.getLogger(TestZKSessionLock.class); - - private static final int sessionTimeoutMs = 2000; - - private ZooKeeperClient zkc; - private ZooKeeperClient zkc0; // used for checking - private OrderedScheduler lockStateExecutor; - - @Before - public void setup() throws Exception { - zkc = ZooKeeperClientBuilder.newBuilder() - .name("zkc") - .uri(DLMTestUtil.createDLMURI(zkPort, "/")) - .sessionTimeoutMs(sessionTimeoutMs) - .zkServers(zkServers) - .zkAclId(null) - .build(); - zkc0 = ZooKeeperClientBuilder.newBuilder() - .name("zkc0") - .uri(DLMTestUtil.createDLMURI(zkPort, "/")) - .sessionTimeoutMs(sessionTimeoutMs) - .zkServers(zkServers) - .zkAclId(null) - .build(); - lockStateExecutor = OrderedScheduler.newSchedulerBuilder() - .numThreads(1) - .build(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - zkc0.close(); - lockStateExecutor.shutdown(); - } - - private static void createLockPath(ZooKeeper zk, String lockPath) throws Exception { - zk.create(lockPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } - - private static String createLockNodeV1(ZooKeeper zk, String lockPath, String clientId) throws Exception { - return zk.create(getLockPathPrefixV1(lockPath), serializeClientId(clientId), - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); - } - - private static String createLockNodeV2(ZooKeeper zk, String lockPath, String clientId) throws Exception { - return zk.create(getLockPathPrefixV2(lockPath, clientId), serializeClientId(clientId), - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); - } - - private static String createLockNodeV3(ZooKeeper zk, String lockPath, String clientId) throws Exception { - return zk.create(getLockPathPrefixV3(lockPath, clientId, zk.getSessionId()), serializeClientId(clientId), - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); - } - - private static String createLockNodeWithBadNodeName(ZooKeeper zk, String lockPath, - String clientId, String badNodeName) throws Exception { - return zk.create(lockPath + "/" + badNodeName, serializeClientId(clientId), - ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); - } - - private static List getLockWaiters(ZooKeeperClient zkc, String lockPath) throws Exception { - List children = zkc.get().getChildren(lockPath, false); - Collections.sort(children, ZKSessionLock.MEMBER_COMPARATOR); - return children; - } - - @Test(timeout = 60000) - public void testParseClientID() throws Exception { - ZooKeeper zk = zkc.get(); - - String lockPath = "/test-parse-clientid"; - String clientId = "test-parse-clientid-" + System.currentTimeMillis(); - Pair lockId = Pair.of(clientId, zk.getSessionId()); - - createLockPath(zk, lockPath); - - // Correct data - String node1 = getLockIdFromPath(createLockNodeV1(zk, lockPath, clientId)); - String node2 = getLockIdFromPath(createLockNodeV2(zk, lockPath, clientId)); - String node3 = getLockIdFromPath(createLockNodeV3(zk, lockPath, clientId)); - - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node1))); - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node2))); - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node3))); - - // Bad Lock Node Name - String node4 = getLockIdFromPath(createLockNodeWithBadNodeName(zk, lockPath, clientId, "member")); - String node5 = getLockIdFromPath(createLockNodeWithBadNodeName(zk, lockPath, clientId, "member_badnode")); - String node6 = getLockIdFromPath( - createLockNodeWithBadNodeName(zk, lockPath, clientId, "member_badnode_badnode")); - String node7 = getLockIdFromPath( - createLockNodeWithBadNodeName(zk, lockPath, clientId, "member_badnode_badnode_badnode")); - String node8 = getLockIdFromPath( - createLockNodeWithBadNodeName(zk, lockPath, clientId, "member_badnode_badnode_badnode_badnode")); - - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node4))); - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node5))); - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node6))); - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node7))); - assertEquals(lockId, Utils.ioResult(asyncParseClientID(zk, lockPath, node8))); - - // Malformed Node Name - String node9 = getLockIdFromPath( - createLockNodeWithBadNodeName(zk, lockPath, clientId, "member_malformed_s12345678_999999")); - assertEquals(Pair.of("malformed", 12345678L), Utils.ioResult(asyncParseClientID(zk, lockPath, node9))); - } - - @Test(timeout = 60000) - public void testParseMemberID() throws Exception { - assertEquals(Integer.MAX_VALUE, parseMemberID("badnode")); - assertEquals(Integer.MAX_VALUE, parseMemberID("badnode_badnode")); - assertEquals(0, parseMemberID("member_000000")); - assertEquals(123, parseMemberID("member_000123")); - } - - @Test(timeout = 60000) - public void testAreLockWaitersInSameSession() throws Exception { - ZooKeeper zk = zkc.get(); - - String lockPath = "/test-are-lock-waiters-in-same-session"; - String clientId1 = "test-are-lock-waiters-in-same-session-1"; - String clientId2 = "test-are-lock-waiters-in-same-session-2"; - - createLockPath(zk, lockPath); - - String node1 = getLockIdFromPath(createLockNodeV3(zk, lockPath, clientId1)); - String node2 = getLockIdFromPath(createLockNodeV3(zk, lockPath, clientId2)); - String node3 = getLockIdFromPath(createLockNodeV3(zk, lockPath, clientId1)); - - assertEquals(node1 + " and " + node3 + " should be in same session.", - true, areLockWaitersInSameSession(node1, node3)); - assertEquals(node1 + " and " + node2 + " should be not in same session.", - false, areLockWaitersInSameSession(node1, node2)); - assertEquals(node3 + " and " + node2 + " should be not in same session.", - false, areLockWaitersInSameSession(node3, node2)); - } - - @Test(timeout = 60000) - public void testExecuteLockAction() throws Exception { - String lockPath = "/test-execute-lock-action"; - String clientId = "test-execute-lock-action-" + System.currentTimeMillis(); - - ZKSessionLock lock = - new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - - final AtomicInteger counter = new AtomicInteger(0); - - // lock action would be executed in same epoch - final CountDownLatch latch1 = new CountDownLatch(1); - lock.executeLockAction(lock.getEpoch(), new LockAction() { - @Override - public void execute() { - counter.incrementAndGet(); - latch1.countDown(); - } - - @Override - public String getActionName() { - return "increment1"; - } - }); - latch1.await(); - assertEquals("counter should be increased in same epoch", 1, counter.get()); - - // lock action would not be executed in same epoch - final CountDownLatch latch2 = new CountDownLatch(1); - lock.executeLockAction(lock.getEpoch() + 1, new LockAction() { - @Override - public void execute() { - counter.incrementAndGet(); - } - - @Override - public String getActionName() { - return "increment2"; - } - }); - lock.executeLockAction(lock.getEpoch(), new LockAction() { - @Override - public void execute() { - latch2.countDown(); - } - - @Override - public String getActionName() { - return "countdown"; - } - }); - latch2.await(); - assertEquals("counter should not be increased in different epochs", 1, counter.get()); - - // lock action would not be executed in same epoch and promise would be satisfied with exception - CompletableFuture promise = new CompletableFuture(); - lock.executeLockAction(lock.getEpoch() + 1, new LockAction() { - @Override - public void execute() { - counter.incrementAndGet(); - } - - @Override - public String getActionName() { - return "increment3"; - } - }, promise); - try { - Utils.ioResult(promise); - fail("Should satisfy promise with epoch changed exception."); - } catch (EpochChangedException ece) { - // expected - } - assertEquals("counter should not be increased in different epochs", 1, counter.get()); - - lockStateExecutor.shutdown(); - } - - /** - * Test lock after unlock is called. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockAfterUnlock() throws Exception { - String lockPath = "/test-lock-after-unlock"; - String clientId = "test-lock-after-unlock"; - - ZKSessionLock lock = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - lock.unlock(); - assertEquals(State.CLOSED, lock.getLockState()); - - try { - lock.tryLock(0, TimeUnit.MILLISECONDS); - fail("Should fail on tryLock since lock state has changed."); - } catch (LockStateChangedException lsce) { - // expected - } - assertEquals(State.CLOSED, lock.getLockState()); - - try { - lock.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - fail("Should fail on tryLock immediately if lock state has changed."); - } catch (LockStateChangedException lsce) { - // expected - } - assertEquals(State.CLOSED, lock.getLockState()); - } - - class DelayFailpointAction extends FailpointUtils.AbstractFailPointAction { - long timeout; - DelayFailpointAction(long timeout) { - this.timeout = timeout; - } - @Override - public boolean checkFailPoint() throws IOException { - try { - Thread.sleep(timeout); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - } - return true; - } - } - - /** - * Test unlock timeout. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testUnlockTimeout() throws Exception { - String name = testNames.getMethodName(); - String lockPath = "/" + name; - String clientId = name; - - createLockPath(zkc.get(), lockPath); - - ZKSessionLock lock = new ZKSessionLock( - zkc, lockPath, clientId, lockStateExecutor, - 1 * 1000 /* op timeout */, NullStatsLogger.INSTANCE, - new DistributedLockContext()); - - lock.tryLock(0, TimeUnit.MILLISECONDS); - assertEquals(State.CLAIMED, lock.getLockState()); - - try { - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_LockUnlockCleanup, - new DelayFailpointAction(60 * 60 * 1000)); - - lock.unlock(); - assertEquals(State.CLOSING, lock.getLockState()); - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_LockUnlockCleanup); - } - } - - /** - * Test try-create after close race condition. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testTryCloseRaceCondition() throws Exception { - String name = testNames.getMethodName(); - String lockPath = "/" + name; - String clientId = name; - - createLockPath(zkc.get(), lockPath); - - ZKSessionLock lock = new ZKSessionLock( - zkc, lockPath, clientId, lockStateExecutor, - 1 * 1000 /* op timeout */, NullStatsLogger.INSTANCE, - new DistributedLockContext()); - - try { - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_LockTryCloseRaceCondition, - FailpointUtils.DEFAULT_ACTION); - - lock.tryLock(0, TimeUnit.MILLISECONDS); - } catch (LockClosedException ex) { - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_LockTryCloseRaceCondition); - } - - assertEquals(State.CLOSED, lock.getLockState()); - List children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - } - - /** - * Test try acquire timeout. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testTryAcquireTimeout() throws Exception { - String name = testNames.getMethodName(); - String lockPath = "/" + name; - String clientId = name; - - createLockPath(zkc.get(), lockPath); - - ZKSessionLock lock = new ZKSessionLock( - zkc, lockPath, clientId, lockStateExecutor, - 1 /* op timeout */, NullStatsLogger.INSTANCE, - new DistributedLockContext()); - - try { - FailpointUtils.setFailpoint(FailpointUtils.FailPointName.FP_LockTryAcquire, - new DelayFailpointAction(60 * 60 * 1000)); - - lock.tryLock(0, TimeUnit.MILLISECONDS); - assertEquals(State.CLOSED, lock.getLockState()); - } catch (LockingException le) { - } catch (Exception e) { - fail("expected locking exception"); - } finally { - FailpointUtils.removeFailpoint(FailpointUtils.FailPointName.FP_LockTryAcquire); - } - } - - @Test(timeout = 60000) - public void testBasicLockUnlock0() throws Exception { - testBasicLockUnlock(0); - } - - @Test(timeout = 60000) - public void testBasicLockUnlock1() throws Exception { - testBasicLockUnlock(Long.MAX_VALUE); - } - - /** - * Test Basic Lock and Unlock. - * - lock should succeed if there is no lock held - * - lock should fail on a success lock - * - unlock should release the held lock - * - * @param timeout - * timeout to wait for the lock - * @throws Exception - */ - private void testBasicLockUnlock(long timeout) throws Exception { - String lockPath = "/test-basic-lock-unlock-" + timeout + System.currentTimeMillis(); - String clientId = "test-basic-lock-unlock"; - - createLockPath(zkc.get(), lockPath); - - ZKSessionLock lock = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - // lock - lock.tryLock(timeout, TimeUnit.MILLISECONDS); - // verification after lock - assertEquals(State.CLAIMED, lock.getLockState()); - List children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(lock.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - - // lock should fail on a success lock - try { - lock.tryLock(timeout, TimeUnit.MILLISECONDS); - fail("Should fail on locking a failure lock."); - } catch (LockStateChangedException lsce) { - // expected - } - assertEquals(State.CLAIMED, lock.getLockState()); - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(lock.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - - // unlock - lock.unlock(); - // verification after unlock - assertEquals(State.CLOSED, lock.getLockState()); - assertEquals(0, getLockWaiters(zkc, lockPath).size()); - } - - /** - * Test lock on non existed lock. - * - lock should fail on a non existed lock. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockOnNonExistedLock() throws Exception { - String lockPath = "/test-lock-on-non-existed-lock"; - String clientId = "test-lock-on-non-existed-lock"; - - ZKSessionLock lock = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - // lock - try { - lock.tryLock(0, TimeUnit.MILLISECONDS); - fail("Should fail on locking a non-existed lock."); - } catch (LockingException le) { - Throwable cause = le.getCause(); - assertTrue(cause instanceof KeeperException); - assertEquals(KeeperException.Code.NONODE, ((KeeperException) cause).code()); - } - assertEquals(State.CLOSED, lock.getLockState()); - - // lock should failed on a failure lock - try { - lock.tryLock(0, TimeUnit.MILLISECONDS); - fail("Should fail on locking a failure lock."); - } catch (LockStateChangedException lsce) { - // expected - } - assertEquals(State.CLOSED, lock.getLockState()); - } - - @Test(timeout = 60000) - public void testLockWhenSomeoneHeldLock0() throws Exception { - testLockWhenSomeoneHeldLock(0); - } - - @Test(timeout = 60000) - public void testLockWhenSomeoneHeldLock1() throws Exception { - testLockWhenSomeoneHeldLock(500); - } - - /** - * Test lock if the lock is already held by someone else. Any lock in this situation will - * fail with current owner. - * - * @param timeout - * timeout to wait for the lock - * @throws Exception - */ - private void testLockWhenSomeoneHeldLock(long timeout) throws Exception { - String lockPath = "/test-lock-nowait-" + timeout + "-" + System.currentTimeMillis(); - String clientId0 = "test-lock-nowait-0-" + System.currentTimeMillis(); - String clientId1 = "test-lock-nowait-1-" + System.currentTimeMillis(); - String clientId2 = "test-lock-nowait-2-" + System.currentTimeMillis(); - - createLockPath(zkc.get(), lockPath); - - ZKSessionLock lock0 = new ZKSessionLock(zkc0, lockPath, clientId0, lockStateExecutor); - ZKSessionLock lock1 = new ZKSessionLock(zkc, lockPath, clientId1, lockStateExecutor); - - lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - // verification after lock0 lock - assertEquals(State.CLAIMED, lock0.getLockState()); - List children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - try { - lock1.tryLock(timeout, TimeUnit.MILLISECONDS); - fail("lock1 should fail on locking since lock0 is holding the lock."); - } catch (OwnershipAcquireFailedException oafe) { - assertEquals(lock0.getLockId().getLeft(), oafe.getCurrentOwner()); - } - // verification after lock1 tryLock - assertEquals(State.CLAIMED, lock0.getLockState()); - assertEquals(State.CLOSED, lock1.getLockState()); - children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - lock0.unlock(); - // verification after unlock lock0 - assertEquals(State.CLOSED, lock0.getLockState()); - assertEquals(0, getLockWaiters(zkc, lockPath).size()); - - ZKSessionLock lock2 = new ZKSessionLock(zkc, lockPath, clientId2, lockStateExecutor); - lock2.tryLock(timeout, TimeUnit.MILLISECONDS); - // verification after lock2 lock - assertEquals(State.CLOSED, lock0.getLockState()); - assertEquals(State.CLOSED, lock1.getLockState()); - assertEquals(State.CLAIMED, lock2.getLockState()); - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(lock2.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - - lock2.unlock(); - } - - @Test(timeout = 60000) - public void testLockWhenPreviousLockZnodeStillExists() throws Exception { - String lockPath = "/test-lock-when-previous-lock-znode-still-exists-" - + System.currentTimeMillis(); - String clientId = "client-id"; - - ZooKeeper zk = zkc.get(); - - createLockPath(zk, lockPath); - - final ZKSessionLock lock0 = new ZKSessionLock(zkc0, lockPath, clientId, lockStateExecutor); - // lock0 lock - lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - - // simulate lock0 expires but znode still exists - final DistributedLockContext context1 = new DistributedLockContext(); - context1.addLockId(lock0.getLockId()); - - final ZKSessionLock lock1 = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor, - 60000, NullStatsLogger.INSTANCE, context1); - lock1.tryLock(0L, TimeUnit.MILLISECONDS); - assertEquals(State.CLAIMED, lock1.getLockState()); - lock1.unlock(); - - final DistributedLockContext context2 = new DistributedLockContext(); - context2.addLockId(lock0.getLockId()); - - final ZKSessionLock lock2 = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor, - 60000, NullStatsLogger.INSTANCE, context2); - lock2.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - assertEquals(State.CLAIMED, lock2.getLockState()); - lock2.unlock(); - - lock0.unlock(); - } - - @Test(timeout = 60000) - public void testWaitForLockUnlock() throws Exception { - testWaitForLockReleased("/test-wait-for-lock-unlock", true); - } - - @Test(timeout = 60000) - public void testWaitForLockExpired() throws Exception { - testWaitForLockReleased("/test-wait-for-lock-expired", false); - } - - /** - * Test lock wait for the lock owner to release the lock. The lock waiter should acquire lock successfully - * if the lock owner unlock or it is expired. - * - * @param lockPath - * lock path - * @param isUnlock - * whether to unlock or expire the lock - * @throws Exception - */ - private void testWaitForLockReleased(String lockPath, boolean isUnlock) throws Exception { - String clientId0 = "test-wait-for-lock-released-0-" + System.currentTimeMillis(); - String clientId1 = "test-wait-for-lock-released-1-" + System.currentTimeMillis(); - - createLockPath(zkc.get(), lockPath); - - final ZKSessionLock lock0 = new ZKSessionLock(zkc0, lockPath, clientId0, lockStateExecutor); - final ZKSessionLock lock1 = new ZKSessionLock(zkc, lockPath, clientId1, lockStateExecutor); - - lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - // verification after lock0 lock - assertEquals(State.CLAIMED, lock0.getLockState()); - List children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - final CountDownLatch lock1DoneLatch = new CountDownLatch(1); - - Thread lock1Thread = new Thread(new Runnable() { - @Override - public void run() { - try { - lock1.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - lock1DoneLatch.countDown(); - } catch (LockingException e) { - logger.error("Failed on locking lock1 : ", e); - } - } - }, "lock1-thread"); - lock1Thread.start(); - - // ensure lock1 is waiting for lock0 - children = awaitWaiters(2, zkc, lockPath); - - if (isUnlock) { - lock0.unlock(); - } else { - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - } - - lock1DoneLatch.await(); - lock1Thread.join(); - - // verification after lock2 lock - if (isUnlock) { - assertEquals(State.CLOSED, lock0.getLockState()); - } else { - assertEquals(State.EXPIRED, lock0.getLockState()); - } - assertEquals(State.CLAIMED, lock1.getLockState()); - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - - lock1.unlock(); - } - - /** - * Test session expired after claimed the lock: lock state should be changed to expired and notify - * the lock listener about expiry. - * - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockListenerOnExpired() throws Exception { - String lockPath = "/test-lock-listener-on-expired"; - String clientId = "test-lock-listener-on-expired-" + System.currentTimeMillis(); - - createLockPath(zkc.get(), lockPath); - - final CountDownLatch expiredLatch = new CountDownLatch(1); - LockListener listener = new LockListener() { - @Override - public void onExpired() { - expiredLatch.countDown(); - } - }; - final ZKSessionLock lock = - new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor).setLockListener(listener); - lock.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - // verification after lock - assertEquals(State.CLAIMED, lock.getLockState()); - List children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(lock.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - - ZooKeeperClientUtils.expireSession(zkc, zkServers, sessionTimeoutMs); - expiredLatch.await(); - assertEquals(State.EXPIRED, lock.getLockState()); - children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - - try { - lock.tryLock(0, TimeUnit.MILLISECONDS); - fail("Should fail on tryLock since lock state has changed."); - } catch (LockStateChangedException lsce) { - // expected - } - - lock.unlock(); - } - - @Test(timeout = 60000) - public void testSessionExpiredBeforeLock0() throws Exception { - testSessionExpiredBeforeLock(0); - } - - @Test(timeout = 60000) - public void testSessionExpiredBeforeLock1() throws Exception { - testSessionExpiredBeforeLock(Long.MAX_VALUE); - } - - /** - * Test Session Expired Before Lock does locking. The lock should be closed since - * all zookeeper operations would be failed. - * - * @param timeout - * timeout to wait for the lock - * @throws Exception - */ - private void testSessionExpiredBeforeLock(long timeout) throws Exception { - String lockPath = "/test-session-expired-before-lock-" + timeout + "-" + System.currentTimeMillis(); - String clientId = "test-session-expired-before-lock-" + System.currentTimeMillis(); - - createLockPath(zkc.get(), lockPath); - final AtomicInteger expireCounter = new AtomicInteger(0); - final CountDownLatch expiredLatch = new CountDownLatch(1); - LockListener listener = new LockListener() { - @Override - public void onExpired() { - expireCounter.incrementAndGet(); - } - }; - final ZKSessionLock lock = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor) - .setLockListener(listener); - // expire session - ZooKeeperClientUtils.expireSession(zkc, zkServers, sessionTimeoutMs); - // submit a runnable to lock state executor to ensure any state changes happened when session expired - lockStateExecutor.executeOrdered(lockPath, () -> expiredLatch.countDown()); - expiredLatch.await(); - // no watcher was registered if never acquired lock successfully - assertEquals(State.INIT, lock.getLockState()); - try { - lock.tryLock(timeout, TimeUnit.MILLISECONDS); - fail("Should fail locking using an expired lock"); - } catch (LockingException le) { - assertTrue(le.getCause() instanceof KeeperException.SessionExpiredException); - } - assertEquals(State.CLOSED, lock.getLockState()); - List children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - } - - @Test(timeout = 60000) - public void testSessionExpiredForLockWaiter() throws Exception { - String lockPath = "/test-session-expired-for-lock-waiter"; - String clientId0 = "test-session-expired-for-lock-waiter-0"; - String clientId1 = "test-session-expired-for-lock-waiter-1"; - - createLockPath(zkc.get(), lockPath); - - final ZKSessionLock lock0 = new ZKSessionLock(zkc0, lockPath, clientId0, lockStateExecutor); - lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - assertEquals(State.CLAIMED, lock0.getLockState()); - List children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - final ZKSessionLock lock1 = new ZKSessionLock(zkc, lockPath, clientId1, lockStateExecutor); - final CountDownLatch lock1DoneLatch = new CountDownLatch(1); - - Thread lock1Thread = new Thread(new Runnable() { - @Override - public void run() { - try { - lock1.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - } catch (OwnershipAcquireFailedException oafe) { - lock1DoneLatch.countDown(); - } catch (LockingException e) { - logger.error("Failed on locking lock1 : ", e); - } - } - }, "lock1-thread"); - lock1Thread.start(); - - // check lock1 is waiting for lock0 - children = awaitWaiters(2, zkc, lockPath); - - assertEquals(2, children.size()); - assertEquals(State.CLAIMED, lock0.getLockState()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - awaitState(State.WAITING, lock1); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(1)))); - - // expire lock1 - ZooKeeperClientUtils.expireSession(zkc, zkServers, sessionTimeoutMs); - - lock1DoneLatch.countDown(); - lock1Thread.join(); - assertEquals(State.CLAIMED, lock0.getLockState()); - assertEquals(State.CLOSED, lock1.getLockState()); - children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - } - - public void awaitState(State state, ZKSessionLock lock) throws InterruptedException { - while (lock.getLockState() != state) { - Thread.sleep(50); - } - } - - public List awaitWaiters(int waiters, ZooKeeperClient zkc, String lockPath) throws Exception { - List children = getLockWaiters(zkc, lockPath); - while (children.size() < waiters) { - Thread.sleep(50); - children = getLockWaiters(zkc, lockPath); - } - return children; - } - - @Test(timeout = 60000) - public void testLockUseSameClientIdButDifferentSessions0() throws Exception { - testLockUseSameClientIdButDifferentSessions(true); - } - - @Test(timeout = 60000) - public void testLockUseSameClientIdButDifferentSessions1() throws Exception { - testLockUseSameClientIdButDifferentSessions(false); - } - - private void testLockUseSameClientIdButDifferentSessions(boolean isUnlock) throws Exception { - String lockPath = "/test-lock-use-same-client-id-but-different-sessions-" - + isUnlock + System.currentTimeMillis(); - String clientId = "test-lock-use-same-client-id-but-different-sessions"; - - createLockPath(zkc.get(), lockPath); - - final ZKSessionLock lock0 = new ZKSessionLock(zkc0, lockPath, clientId, lockStateExecutor); - - lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - // lock1_0 couldn't claim ownership since owner is in a different zk session. - final ZKSessionLock lock1_0 = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - try { - lock1_0.tryLock(0, TimeUnit.MILLISECONDS); - fail("Should fail locking since the lock is held in a different zk session."); - } catch (OwnershipAcquireFailedException oafe) { - assertEquals(clientId, oafe.getCurrentOwner()); - } - assertEquals(State.CLOSED, lock1_0.getLockState()); - List children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - // lock1_1 would wait the ownership - final ZKSessionLock lock1_1 = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - final CountDownLatch lock1DoneLatch = new CountDownLatch(1); - - Thread lock1Thread = new Thread(new Runnable() { - @Override - public void run() { - try { - lock1_1.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - lock1DoneLatch.countDown(); - } catch (LockingException e) { - logger.error("Failed on locking lock1 : ", e); - } - } - }, "lock1-thread"); - lock1Thread.start(); - - // check lock1 is waiting for lock0 - children = awaitWaiters(2, zkc, lockPath); - - logger.info("Found {} lock waiters : {}", children.size(), children); - - assertEquals(2, children.size()); - assertEquals(State.CLAIMED, lock0.getLockState()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - awaitState(State.WAITING, lock1_1); - assertEquals(lock1_1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(1)))); - - if (isUnlock) { - lock0.unlock(); - } else { - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - } - lock1DoneLatch.await(); - lock1Thread.join(); - - // verification - if (isUnlock) { - assertEquals(State.CLOSED, lock0.getLockState()); - } else { - assertEquals(State.EXPIRED, lock0.getLockState()); - } - assertEquals(State.CLAIMED, lock1_1.getLockState()); - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(lock1_1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - - lock1_1.unlock(); - } - - @Test(timeout = 60000) - public void testLockWithMultipleSiblingWaiters() throws Exception { - String lockPath = "/test-lock-with-multiple-sibling-waiters"; - String clientId = "client-id"; - - createLockPath(zkc.get(), lockPath); - - final ZKSessionLock lock0 = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - final ZKSessionLock lock1 = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - final ZKSessionLock lock2 = new ZKSessionLock(zkc, lockPath, clientId, lockStateExecutor); - - lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - lock1.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - lock2.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - - List children = awaitWaiters(3, zkc, lockPath); - - assertEquals(3, children.size()); - assertEquals(State.CLAIMED, lock0.getLockState()); - assertEquals(State.CLAIMED, lock1.getLockState()); - assertEquals(State.CLAIMED, lock2.getLockState()); - - lock0.unlock(); - lock1.unlock(); - lock2.unlock(); - } - - /** - * Immediate lock and unlock first lock. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockWhenSiblingUseDifferentLockId0() throws Exception { - testLockWhenSiblingUseDifferentLockId(0, true); - } - - /** - * Immediate lock and expire first lock. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockWhenSiblingUseDifferentLockId1() throws Exception { - testLockWhenSiblingUseDifferentLockId(0, false); - } - - /** - * Wait Lock and unlock lock0_0 and lock1. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockWhenSiblingUseDifferentLockId2() throws Exception { - testLockWhenSiblingUseDifferentLockId(Long.MAX_VALUE, true); - } - - /** - * Wait Lock and expire first & third lock. - * @throws Exception - */ - @Test(timeout = 60000) - public void testLockWhenSiblingUseDifferentLockId3() throws Exception { - testLockWhenSiblingUseDifferentLockId(Long.MAX_VALUE, false); - } - - private void testLockWhenSiblingUseDifferentLockId(long timeout, final boolean isUnlock) throws Exception { - String lockPath = "/test-lock-when-sibling-use-different-lock-id-" + timeout - + "-" + isUnlock + "-" + System.currentTimeMillis(); - String clientId0 = "client-id-0"; - String clientId1 = "client-id-1"; - - createLockPath(zkc.get(), lockPath); - - final ZKSessionLock lock0_0 = new ZKSessionLock(zkc0, lockPath, clientId0, lockStateExecutor); - final ZKSessionLock lock0_1 = new ZKSessionLock(zkc0, lockPath, clientId0, lockStateExecutor); - final ZKSessionLock lock1 = new ZKSessionLock(zkc, lockPath, clientId1, lockStateExecutor); - - lock0_0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - - // lock1 wait for the lock ownership. - final CountDownLatch lock1DoneLatch = new CountDownLatch(1); - Thread lock1Thread = new Thread(new Runnable() { - @Override - public void run() { - try { - lock1.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - lock1DoneLatch.countDown(); - } catch (LockingException e) { - logger.error("Failed on locking lock1 : ", e); - } - } - }, "lock1-thread"); - lock1Thread.start(); - - // check lock1 is waiting for lock0_0 - List children = awaitWaiters(2, zkc, lockPath); - - assertEquals(2, children.size()); - assertEquals(State.CLAIMED, lock0_0.getLockState()); - assertEquals(lock0_0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - awaitState(State.WAITING, lock1); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(1)))); - - final CountDownLatch lock0DoneLatch = new CountDownLatch(1); - final AtomicReference ownerFromLock0 = new AtomicReference(null); - Thread lock0Thread = null; - if (timeout == 0) { - try { - lock0_1.tryLock(0, TimeUnit.MILLISECONDS); - fail("Should fail on locking if sibling is using differnt lock id."); - } catch (OwnershipAcquireFailedException oafe) { - assertEquals(clientId0, oafe.getCurrentOwner()); - } - assertEquals(State.CLOSED, lock0_1.getLockState()); - children = getLockWaiters(zkc, lockPath); - assertEquals(2, children.size()); - assertEquals(State.CLAIMED, lock0_0.getLockState()); - assertEquals(lock0_0.getLockId(), - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - assertEquals(State.WAITING, lock1.getLockState()); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(1)))); - } else { - lock0Thread = new Thread(new Runnable() { - @Override - public void run() { - try { - lock0_1.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - if (isUnlock) { - lock0DoneLatch.countDown(); - } - } catch (OwnershipAcquireFailedException oafe) { - if (!isUnlock) { - ownerFromLock0.set(oafe.getCurrentOwner()); - lock0DoneLatch.countDown(); - } - } catch (LockingException le) { - logger.error("Failed on locking lock0_1 : ", le); - } - } - }, "lock0-thread"); - lock0Thread.start(); - - // check lock1 is waiting for lock0_0 - children = awaitWaiters(3, zkc, lockPath); - - assertEquals(3, children.size()); - assertEquals(State.CLAIMED, lock0_0.getLockState()); - assertEquals(lock0_0.getLockId(), - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - awaitState(State.WAITING, lock1); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(1)))); - awaitState(State.WAITING, lock0_1); - assertEquals(lock0_1.getLockId(), - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(2)))); - } - - if (isUnlock) { - lock0_0.unlock(); - } else { - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - } - - lock1DoneLatch.await(); - lock1Thread.join(); - - // check the state of lock0_0 - if (isUnlock) { - assertEquals(State.CLOSED, lock0_0.getLockState()); - } else { - assertEquals(State.EXPIRED, lock0_0.getLockState()); - } - - if (timeout == 0) { - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(State.CLAIMED, lock1.getLockState()); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - } else { - assertNotNull(lock0Thread); - if (!isUnlock) { - // both lock0_0 and lock0_1 would be expired - lock0DoneLatch.await(); - lock0Thread.join(); - - assertEquals(clientId0, ownerFromLock0.get()); - assertEquals(State.CLOSED, lock0_1.getLockState()); - - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(State.CLAIMED, lock1.getLockState()); - assertEquals(lock1.getLockId(), - Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - } else { - children = getLockWaiters(zkc, lockPath); - assertEquals(2, children.size()); - assertEquals(State.CLAIMED, lock1.getLockState()); - assertEquals(lock1.getLockId(), - Utils.ioResult(asyncParseClientID(zkc.get(), lockPath, children.get(0)))); - assertEquals(State.WAITING, lock0_1.getLockState()); - assertEquals(lock0_1.getLockId(), - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(1)))); - } - } - - lock1.unlock(); - - if (timeout != 0 && isUnlock) { - lock0DoneLatch.await(); - lock0Thread.join(); - - children = getLockWaiters(zkc, lockPath); - assertEquals(1, children.size()); - assertEquals(State.CLAIMED, lock0_1.getLockState()); - assertEquals(lock0_1.getLockId(), - Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - } - } - - @Test(timeout = 60000) - public void testLockWhenSiblingUseSameLockId0() throws Exception { - testLockWhenSiblingUseSameLockId(0, true); - } - - @Test(timeout = 60000) - public void testLockWhenSiblingUseSameLockId1() throws Exception { - testLockWhenSiblingUseSameLockId(0, false); - } - - @Test(timeout = 60000) - public void testLockWhenSiblingUseSameLockId2() throws Exception { - testLockWhenSiblingUseSameLockId(Long.MAX_VALUE, true); - } - - @Test(timeout = 60000) - public void testLockWhenSiblingUseSameLockId3() throws Exception { - testLockWhenSiblingUseSameLockId(Long.MAX_VALUE, false); - } - - private void testLockWhenSiblingUseSameLockId(long timeout, final boolean isUnlock) throws Exception { - String lockPath = "/test-lock-when-sibling-use-same-lock-id-" + timeout - + "-" + isUnlock + "-" + System.currentTimeMillis(); - String clientId = "client-id"; - - createLockPath(zkc.get(), lockPath); - - final ZKSessionLock lock0 = new ZKSessionLock(zkc0, lockPath, clientId, lockStateExecutor); - final ZKSessionLock lock1 = new ZKSessionLock(zkc0, lockPath, clientId, lockStateExecutor); - - lock0.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - List children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(State.CLAIMED, lock0.getLockState()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - - lock1.tryLock(timeout, TimeUnit.MILLISECONDS); - children = getLockWaiters(zkc0, lockPath); - assertEquals(2, children.size()); - assertEquals(State.CLAIMED, lock0.getLockState()); - assertEquals(lock0.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - assertEquals(State.CLAIMED, lock1.getLockState()); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(1)))); - - if (isUnlock) { - lock0.unlock(); - assertEquals(State.CLOSED, lock0.getLockState()); - children = getLockWaiters(zkc0, lockPath); - assertEquals(1, children.size()); - assertEquals(State.CLAIMED, lock1.getLockState()); - assertEquals(lock1.getLockId(), Utils.ioResult(asyncParseClientID(zkc0.get(), lockPath, children.get(0)))); - lock1.unlock(); - } else { - ZooKeeperClientUtils.expireSession(zkc0, zkServers, sessionTimeoutMs); - final CountDownLatch latch = new CountDownLatch(1); - lockStateExecutor.executeOrdered(lockPath, () -> latch.countDown()); - latch.await(); - children = getLockWaiters(zkc, lockPath); - assertEquals(0, children.size()); - assertEquals(State.EXPIRED, lock0.getLockState()); - assertEquals(State.EXPIRED, lock1.getLockState()); - } - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestPerStreamLogSegmentCache.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestPerStreamLogSegmentCache.java deleted file mode 100644 index c31073bb8d2..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestPerStreamLogSegmentCache.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.logsegment; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.LogSegmentMetadata; -import org.apache.distributedlog.exceptions.UnexpectedException; -import org.junit.Test; - - - -/** - * Test Case for Per Stream Log Segment Cache. - */ -public class TestPerStreamLogSegmentCache { - - @Test(timeout = 60000) - public void testBasicOperations() { - LogSegmentMetadata metadata = - DLMTestUtil.completedLogSegment("/segment1", 1L, 1L, 100L, 100, 1L, 99L, 0L); - String name = DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(1L); - - PerStreamLogSegmentCache cache = new PerStreamLogSegmentCache("test-basic-operations"); - assertNull("No log segment " + name + " should be cached", cache.get(name)); - cache.add(name, metadata); - LogSegmentMetadata metadataRetrieved = cache.get(name); - assertNotNull("log segment " + name + " should be cached", metadataRetrieved); - assertEquals("Wrong log segment metadata returned for " + name, - metadata, metadataRetrieved); - LogSegmentMetadata metadataRemoved = cache.remove(name); - assertNull("log segment " + name + " should be removed from cache", cache.get(name)); - assertEquals("Wrong log segment metadata removed for " + name, - metadata, metadataRemoved); - assertNull("No log segment " + name + " to be removed", cache.remove(name)); - } - - @Test(timeout = 60000) - public void testDiff() { - PerStreamLogSegmentCache cache = new PerStreamLogSegmentCache("test-diff"); - // add 5 completed log segments - for (int i = 1; i <= 5; i++) { - LogSegmentMetadata metadata = - DLMTestUtil.completedLogSegment("/segment" + i, i, i, i * 100L, 100, i, 99L, 0L); - String name = DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i); - cache.add(name, metadata); - } - // add one inprogress log segment - LogSegmentMetadata inprogress = - DLMTestUtil.inprogressLogSegment("/inprogress-6", 6, 600L, 6); - String name = DLMTestUtil.inprogressZNodeName(6); - cache.add(name, inprogress); - - // deleted first 2 completed log segments and completed the last one - Set segmentRemoved = Sets.newHashSet(); - for (int i = 1; i <= 2; i++) { - segmentRemoved.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i)); - } - segmentRemoved.add((DLMTestUtil.inprogressZNodeName(6))); - Set segmentReceived = Sets.newHashSet(); - Set segmentAdded = Sets.newHashSet(); - for (int i = 3; i <= 6; i++) { - segmentReceived.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i)); - if (i == 6) { - segmentAdded.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i)); - } - } - - Pair, Set> segmentChanges = cache.diff(segmentReceived); - assertTrue("Should remove " + segmentRemoved + ", but removed " + segmentChanges.getRight(), - Sets.difference(segmentRemoved, segmentChanges.getRight()).isEmpty()); - assertTrue("Should add " + segmentAdded + ", but added " + segmentChanges.getLeft(), - Sets.difference(segmentAdded, segmentChanges.getLeft()).isEmpty()); - } - - @Test(timeout = 60000) - public void testUpdate() { - PerStreamLogSegmentCache cache = new PerStreamLogSegmentCache("test-update"); - // add 5 completed log segments - for (int i = 1; i <= 5; i++) { - LogSegmentMetadata metadata = - DLMTestUtil.completedLogSegment("/segment" + i, i, i, i * 100L, 100, i, 99L, 0L); - String name = DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i); - cache.add(name, metadata); - } - // add one inprogress log segment - LogSegmentMetadata inprogress = - DLMTestUtil.inprogressLogSegment("/inprogress-6", 6, 600L, 6); - String name = DLMTestUtil.inprogressZNodeName(6); - cache.add(name, inprogress); - - // deleted first 2 completed log segments and completed the last one - Set segmentRemoved = Sets.newHashSet(); - for (int i = 1; i <= 2; i++) { - segmentRemoved.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i)); - } - segmentRemoved.add((DLMTestUtil.inprogressZNodeName(6))); - Set segmentReceived = Sets.newHashSet(); - Map segmentAdded = Maps.newHashMap(); - for (int i = 3; i <= 6; i++) { - segmentReceived.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i)); - if (i == 6) { - segmentAdded.put(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(i), - DLMTestUtil.completedLogSegment("/segment" + i, i, i, i * 100L, 100, i, 99L, 0L)); - } - } - - // update the cache - cache.update(segmentRemoved, segmentAdded); - for (String segment : segmentRemoved) { - assertNull("Segment " + segment + " should be removed.", cache.get(segment)); - } - for (String segment : segmentReceived) { - assertNotNull("Segment " + segment + " should not be removed", cache.get(segment)); - } - for (Map.Entry entry : segmentAdded.entrySet()) { - assertEquals("Segment " + entry.getKey() + " should be added.", - entry.getValue(), entry.getValue()); - } - } - - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testGapDetection() throws Exception { - PerStreamLogSegmentCache cache = new PerStreamLogSegmentCache("test-gap-detection"); - cache.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(1L), - DLMTestUtil.completedLogSegment("/segment-1", 1L, 1L, 100L, 100, 1L, 99L, 0L)); - cache.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(3L), - DLMTestUtil.completedLogSegment("/segment-3", 3L, 3L, 300L, 100, 3L, 99L, 0L)); - cache.getLogSegments(LogSegmentMetadata.COMPARATOR); - } - - @Test(timeout = 60000) - public void testGapDetectionOnLogSegmentsWithoutLogSegmentSequenceNumber() throws Exception { - PerStreamLogSegmentCache cache = new PerStreamLogSegmentCache("test-gap-detection"); - LogSegmentMetadata segment1 = - DLMTestUtil.completedLogSegment("/segment-1", 1L, 1L, 100L, 100, 1L, 99L, 0L) - .mutator().setVersion(LogSegmentMetadata.LogSegmentMetadataVersion.VERSION_V1_ORIGINAL).build(); - cache.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(1L), segment1); - LogSegmentMetadata segment3 = - DLMTestUtil.completedLogSegment("/segment-3", 3L, 3L, 300L, 100, 3L, 99L, 0L) - .mutator().setVersion(LogSegmentMetadata.LogSegmentMetadataVersion.VERSION_V2_LEDGER_SEQNO).build(); - cache.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(3L), segment3); - List expectedList = Lists.asList(segment1, new LogSegmentMetadata[] { segment3 }); - List resultList = cache.getLogSegments(LogSegmentMetadata.COMPARATOR); - assertEquals(expectedList, resultList); - } - - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testSameLogSegment() throws Exception { - PerStreamLogSegmentCache cache = new PerStreamLogSegmentCache("test-same-log-segment"); - List expectedList = Lists.newArrayListWithExpectedSize(2); - LogSegmentMetadata inprogress = - DLMTestUtil.inprogressLogSegment("/inprogress-1", 1L, 1L, 1L); - expectedList.add(inprogress); - cache.add(DLMTestUtil.inprogressZNodeName(1L), inprogress); - LogSegmentMetadata completed = - DLMTestUtil.completedLogSegment("/segment-1", 1L, 1L, 100L, 100, 1L, 99L, 0L); - expectedList.add(completed); - cache.add(DLMTestUtil.completedLedgerZNodeNameWithLogSegmentSequenceNumber(1L), completed); - - cache.getLogSegments(LogSegmentMetadata.COMPARATOR); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestRollingPolicy.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestRollingPolicy.java deleted file mode 100644 index 246d4f83d5c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/logsegment/TestRollingPolicy.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.logsegment; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.apache.distributedlog.common.util.Sizable; -import org.junit.Test; - - -/** - * Test Case for {@link RollingPolicy}s. - */ -public class TestRollingPolicy { - - static class TestSizable implements Sizable { - - long size; - - TestSizable(long size) { - this.size = size; - } - - @Override - public long size() { - return size; - } - } - - @Test(timeout = 60000) - public void testTimeBasedRollingPolicy() { - TimeBasedRollingPolicy policy1 = new TimeBasedRollingPolicy(Long.MAX_VALUE); - TestSizable maxSize = new TestSizable(Long.MAX_VALUE); - assertFalse(policy1.shouldRollover(maxSize, System.currentTimeMillis())); - - long currentMs = System.currentTimeMillis(); - TimeBasedRollingPolicy policy2 = new TimeBasedRollingPolicy(1000); - assertTrue(policy2.shouldRollover(maxSize, currentMs - 2 * 1000)); - } - - @Test(timeout = 60000) - public void testSizeBasedRollingPolicy() { - SizeBasedRollingPolicy policy = new SizeBasedRollingPolicy(1000); - TestSizable sizable1 = new TestSizable(10); - assertFalse(policy.shouldRollover(sizable1, 0L)); - TestSizable sizable2 = new TestSizable(10000); - assertTrue(policy.shouldRollover(sizable2, 0L)); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestDLMetadata.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestDLMetadata.java deleted file mode 100644 index 9f0d86a20da..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestDLMetadata.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.metadata; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.URI; -import org.apache.distributedlog.LocalDLMEmulator; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.distributedlog.impl.metadata.BKDLConfig; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.data.Stat; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - - - - -/** - * Test Case for {@link DLMetadata}s. - */ -public class TestDLMetadata extends ZooKeeperClusterTestCase { - - private static final BKDLConfig bkdlConfig = - new BKDLConfig("127.0.0.1:7000", "127.0.0.1:7000", - "127.0.0.1:7000", "127.0.0.1:7000", "ledgers"); - private static final BKDLConfig bkdlConfig2 = - new BKDLConfig("127.0.0.1:7001", "127.0.0.1:7002", - "127.0.0.1:7003", "127.0.0.1:7004", "ledgers2"); - - private ZooKeeper zkc; - - @Before - public void setup() throws Exception { - zkc = LocalDLMEmulator.connectZooKeeper("127.0.0.1", zkPort); - } - - @After - public void teardown() throws Exception { - zkc.close(); - } - - private URI createURI(String path) { - return URI.create("distributedlog://127.0.0.1:" + zkPort + path); - } - - @Test(timeout = 60000) - public void testBadMetadata() throws Exception { - URI uri = createURI("/"); - try { - DLMetadata.deserialize(uri, new byte[0]); - fail("Should fail to deserialize invalid metadata"); - } catch (IOException ie) { - // expected - } - try { - DLMetadata.deserialize(uri, new DLMetadata("unknown", bkdlConfig).serialize()); - fail("Should fail to deserialize due to unknown dl type."); - } catch (IOException ie) { - // expected - } - try { - DLMetadata.deserialize(uri, new DLMetadata(DLMetadata.BK_DL_TYPE, bkdlConfig, 9999).serialize()); - fail("Should fail to deserialize due to invalid version."); - } catch (IOException ie) { - // expected - } - byte[] data = new DLMetadata(DLMetadata.BK_DL_TYPE, bkdlConfig).serialize(); - // truncate data - byte[] badData = new byte[data.length - 3]; - System.arraycopy(data, 0, badData, 0, badData.length); - try { - DLMetadata.deserialize(uri, badData); - fail("Should fail to deserialize truncated data."); - } catch (IOException ie) { - // expected - } - } - - @Test(timeout = 60000) - public void testGoodMetadata() throws Exception { - URI uri = createURI("/"); - byte[] data = new DLMetadata(DLMetadata.BK_DL_TYPE, bkdlConfig).serialize(); - DLMetadata deserailized = DLMetadata.deserialize(uri, data); - assertEquals(bkdlConfig, deserailized.getDLConfig()); - } - - @Test(timeout = 60000) - public void testWriteMetadata() throws Exception { - DLMetadata metadata = new DLMetadata(DLMetadata.BK_DL_TYPE, bkdlConfig); - try { - metadata.create(createURI("//metadata")); - fail("Should fail due to invalid uri."); - } catch (IllegalArgumentException e) { - // expected - } - URI uri = createURI("/metadata"); - metadata.create(uri); - // create on existed path - try { - metadata.create(uri); - fail("Should fail when create on existed path"); - } catch (IOException e) { - // expected - } - // update on unexisted path - try { - metadata.update(createURI("/unexisted")); - fail("Should fail when update on unexisted path"); - } catch (IOException e) { - // expected - } - byte[] data = zkc.getData("/metadata", false, new Stat()); - assertEquals(bkdlConfig, DLMetadata.deserialize(uri, data).getDLConfig()); - // update on existed path - DLMetadata newMetadata = new DLMetadata(DLMetadata.BK_DL_TYPE, bkdlConfig2); - newMetadata.update(createURI("/metadata")); - byte[] newData = zkc.getData("/metadata", false, new Stat()); - assertEquals(bkdlConfig2, DLMetadata.deserialize(uri, newData).getDLConfig()); - } - - // Missing dlZkServersForWriter, dlZkServersForReader default to configured server. - @Test(timeout = 60000) - public void testMetadataWithoutDLZKServers() throws Exception { - testMetadataWithOrWithoutZkServers( - "/metadata-without-dlzk-servers", - null, null, "127.0.0.1:7003", "127.0.0.1:7004", - "127.0.0.1:" + zkPort, "127.0.0.1:" + zkPort, "127.0.0.1:7003", "127.0.0.1:7004"); - } - - @Test(timeout = 60000) - public void testMetadataWithoutDLZKServersForRead() throws Exception { - testMetadataWithOrWithoutZkServers( - "/metadata-without-dlzk-servers-for-read", - "127.0.0.1:7001", null, "127.0.0.1:7003", "127.0.0.1:7004", - "127.0.0.1:7001", "127.0.0.1:7001", "127.0.0.1:7003", "127.0.0.1:7004"); - } - - @Test(timeout = 60000) - public void testMetadataWithoutBKZKServersForRead() throws Exception { - testMetadataWithOrWithoutZkServers( - "/metadata-without-bkzk-servers-for-read", - "127.0.0.1:7001", null, "127.0.0.1:7003", null, - "127.0.0.1:7001", "127.0.0.1:7001", "127.0.0.1:7003", "127.0.0.1:7003"); - } - - private void testMetadataWithOrWithoutZkServers( - String metadataPath, - String dlZkServersForWriter, String dlZkServersForReader, - String bkZkServersForWriter, String bkZkServersForReader, - String expectedDlZkServersForWriter, String expectedDlZkServersForReader, - String expectedBkZkServersForWriter, String expectedBkZkServersForReader - ) throws Exception { - BKDLConfig bkdlConfig = new BKDLConfig(dlZkServersForWriter, dlZkServersForReader, - bkZkServersForWriter, bkZkServersForReader, "ledgers"); - BKDLConfig expectedBKDLConfig = - new BKDLConfig(expectedDlZkServersForWriter, expectedDlZkServersForReader, - expectedBkZkServersForWriter, expectedBkZkServersForReader, "ledgers"); - URI uri = createURI(metadataPath); - DLMetadata metadata = new DLMetadata(DLMetadata.BK_DL_TYPE, bkdlConfig); - metadata.create(uri); - // read serialized metadata - byte[] data = zkc.getData(metadataPath, false, new Stat()); - assertEquals(expectedBKDLConfig, DLMetadata.deserialize(uri, data).getDLConfig()); - } - - @Test(timeout = 60000) - public void testMetadataMissingRequiredFields() throws Exception { - BKDLConfig bkdlConfig = new BKDLConfig(null, null, null, null, "ledgers"); - URI uri = createURI("/metadata-missing-fields"); - DLMetadata metadata = new DLMetadata(DLMetadata.BK_DL_TYPE, bkdlConfig); - metadata.create(uri); - // read serialized metadata - byte[] data = zkc.getData("/metadata-missing-fields", false, new Stat()); - try { - DLMetadata.deserialize(uri, data); - fail("Should fail on deserializing metadata missing fields"); - } catch (IOException ioe) { - // expected - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogMetadata.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogMetadata.java deleted file mode 100644 index ade31594380..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogMetadata.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.metadata; - - -import static org.apache.distributedlog.metadata.LogMetadata.ALLOCATION_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.LOCK_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.LOGSEGMENTS_PATH; -import static org.apache.distributedlog.metadata.LogMetadata.MAX_TXID_PATH; -import static org.junit.Assert.assertEquals; - -import java.net.URI; -import org.apache.distributedlog.DLMTestUtil; -import org.junit.Test; - - - - -/** - * Test Case for {@link LogMetadata}s. - */ -public class TestLogMetadata { - - @Test(timeout = 60000) - public void testGetPaths() throws Exception { - String rootPath = "/test-get-paths"; - URI uri = DLMTestUtil.createDLMURI(2181, rootPath); - String logName = "test-log"; - String logIdentifier = ""; - String logRootPath = uri.getPath() + "/" + logName + "/" + logIdentifier; - String logSegmentName = "test-segment"; - - LogMetadata logMetadata = new LogMetadata(uri, logName, logIdentifier); - assertEquals("wrong log name", logName, logMetadata.getLogName()); - assertEquals("wrong root path", logRootPath, logMetadata.getLogRootPath()); - assertEquals("wrong log segments path", - logRootPath + LOGSEGMENTS_PATH, - logMetadata.getLogSegmentsPath()); - assertEquals("wrong log segment path", - logRootPath + LOGSEGMENTS_PATH + "/" + logSegmentName, - logMetadata.getLogSegmentPath(logSegmentName)); - assertEquals("wrong lock path", - logRootPath + LOCK_PATH, logMetadata.getLockPath()); - assertEquals("wrong max tx id path", - logRootPath + MAX_TXID_PATH, logMetadata.getMaxTxIdPath()); - assertEquals("wrong allocation path", - logRootPath + ALLOCATION_PATH, logMetadata.getAllocationPath()); - assertEquals("wrong qualified name", - logName + ":" + logIdentifier, logMetadata.getFullyQualifiedName()); - } - - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogSegmentMetadataStoreUpdater.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogSegmentMetadataStoreUpdater.java deleted file mode 100644 index a7b6f7fa987..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/metadata/TestLogSegmentMetadataStoreUpdater.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.metadata; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.LogRecordWithDLSN; -import org.apache.distributedlog.LogSegmentMetadata; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.distributedlog.impl.ZKLogSegmentMetadataStore; -import org.apache.distributedlog.logsegment.LogSegmentMetadataStore; -import org.apache.distributedlog.util.Utils; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -/** - * Test update for {@link LogSegmentMetadataStore}s. - */ -public class TestLogSegmentMetadataStoreUpdater extends ZooKeeperClusterTestCase { - - static final Logger LOG = LoggerFactory.getLogger(TestLogSegmentMetadataStoreUpdater.class); - - private ZooKeeperClient zkc; - private OrderedScheduler scheduler; - private LogSegmentMetadataStore metadataStore; - private DistributedLogConfiguration conf = new DistributedLogConfiguration() - .setDLLedgerMetadataLayoutVersion(LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - - @Before - public void setup() throws Exception { - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-logsegment-metadata-store-updater") - .numThreads(1) - .build(); - zkc = TestZooKeeperClientBuilder.newBuilder() - .uri(createURI("/")) - .sessionTimeoutMs(10000) - .build(); - metadataStore = new ZKLogSegmentMetadataStore(conf, zkc, scheduler); - } - - @After - public void tearDown() throws Exception { - metadataStore.close(); - scheduler.shutdown(); - zkc.close(); - } - - private URI createURI(String path) { - return URI.create("distributedlog://127.0.0.1:" + zkPort + path); - } - - Map readLogSegments(String ledgerPath) throws Exception { - return DLMTestUtil.readLogSegments(zkc, ledgerPath); - } - - @Test(timeout = 60000) - public void testChangeSequenceNumber() throws Exception { - String ledgerPath = "/testChangeSequenceNumber"; - zkc.get().create(ledgerPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - Map completedLogSegments = new HashMap(); - // Create 5 completed log segments - for (int i = 1; i <= 5; i++) { - LogSegmentMetadata segment = - DLMTestUtil.completedLogSegment(ledgerPath, i, (i - 1) * 100, i * 100 - 1, 100, i, 100, 0); - completedLogSegments.put(((long) i), segment); - LOG.info("Create completed segment {} : {}", segment.getZkPath(), segment); - segment.write(zkc); - } - // Create a smaller inprogress log segment - long inprogressSeqNo = 3; - LogSegmentMetadata segment = - DLMTestUtil.inprogressLogSegment(ledgerPath, inprogressSeqNo, 5 * 100, inprogressSeqNo); - LOG.info("Create inprogress segment {} : {}", segment.getZkPath(), segment); - segment.write(zkc); - - Map segmentList = readLogSegments(ledgerPath); - assertEquals(5, segmentList.size()); - - // Dryrun - MetadataUpdater dryrunUpdater = new DryrunLogSegmentMetadataStoreUpdater(conf, metadataStore); - Utils.ioResult(dryrunUpdater.changeSequenceNumber(segment, 6L)); - - segmentList = readLogSegments(ledgerPath); - assertEquals(5, segmentList.size()); - - // Fix the inprogress log segments - - MetadataUpdater updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(conf, metadataStore); - Utils.ioResult(updater.changeSequenceNumber(segment, 6L)); - - segmentList = readLogSegments(ledgerPath); - assertEquals(6, segmentList.size()); - - // check first 5 log segments - for (int i = 1; i <= 5; i++) { - LogSegmentMetadata s = segmentList.get((long) i); - assertNotNull(s); - assertEquals(completedLogSegments.get((long) i), s); - } - - // get log segment 6 - LogSegmentMetadata segmentChanged = segmentList.get(6L); - assertNotNull(segmentChanged); - assertEquals(6L, segmentChanged.getLogSegmentSequenceNumber()); - assertTrue(segmentChanged.isInProgress()); - assertEquals(5 * 100, segmentChanged.getFirstTxId()); - assertEquals(3L, segmentChanged.getLogSegmentId()); - } - - @Test(timeout = 60000) - public void testUpdateLastDLSN() throws Exception { - String ledgerPath = "/testUpdateLastDLSN"; - zkc.get().create(ledgerPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - // Create 1 completed log segment - LogSegmentMetadata completedLogSegment = - DLMTestUtil.completedLogSegment(ledgerPath, 1L, 0L, 99L, 100, 1L, 99L, 0L); - completedLogSegment.write(zkc); - // Create 1 inprogress log segment - LogSegmentMetadata inprogressLogSegment = DLMTestUtil.inprogressLogSegment(ledgerPath, 2L, 100L, 2L); - inprogressLogSegment.write(zkc); - - DLSN badLastDLSN = new DLSN(99L, 0L, 0L); - DLSN goodLastDLSN1 = new DLSN(1L, 100L, 0L); - DLSN goodLastDLSN2 = new DLSN(2L, 200L, 0L); - - LogRecordWithDLSN badRecord = DLMTestUtil.getLogRecordWithDLSNInstance(badLastDLSN, 100L); - LogRecordWithDLSN goodRecord1 = DLMTestUtil.getLogRecordWithDLSNInstance(goodLastDLSN1, 100L); - LogRecordWithDLSN goodRecord2 = DLMTestUtil.getLogRecordWithDLSNInstance(goodLastDLSN2, 200L); - - // Dryrun - MetadataUpdater dryrunUpdater = new DryrunLogSegmentMetadataStoreUpdater(conf, metadataStore); - try { - Utils.ioResult(dryrunUpdater.updateLastRecord(completedLogSegment, badRecord)); - fail("Should fail on updating dlsn that in different log segment"); - } catch (IllegalArgumentException iae) { - // expected - } - try { - Utils.ioResult(dryrunUpdater.updateLastRecord(inprogressLogSegment, goodRecord2)); - fail("Should fail on updating dlsn for an inprogress log segment"); - } catch (IllegalStateException ise) { - // expected - } - LogSegmentMetadata updatedCompletedLogSegment = - Utils.ioResult(dryrunUpdater.updateLastRecord(completedLogSegment, goodRecord1)); - assertEquals(goodLastDLSN1, updatedCompletedLogSegment.getLastDLSN()); - assertEquals(goodRecord1.getTransactionId(), updatedCompletedLogSegment.getLastTxId()); - assertTrue(updatedCompletedLogSegment.isRecordLastPositioninThisSegment(goodRecord1)); - - Map segmentList = readLogSegments(ledgerPath); - assertEquals(2, segmentList.size()); - - LogSegmentMetadata readCompletedLogSegment = segmentList.get(1L); - assertNotNull(readCompletedLogSegment); - assertEquals(completedLogSegment, readCompletedLogSegment); - - LogSegmentMetadata readInprogressLogSegment = segmentList.get(2L); - assertNotNull(readInprogressLogSegment); - assertEquals(inprogressLogSegment, readInprogressLogSegment); - - // Fix the last dlsn - MetadataUpdater updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(conf, metadataStore); - try { - Utils.ioResult(updater.updateLastRecord(completedLogSegment, badRecord)); - fail("Should fail on updating dlsn that in different log segment"); - } catch (IllegalArgumentException iae) { - // expected - } - try { - Utils.ioResult(updater.updateLastRecord(inprogressLogSegment, goodRecord2)); - fail("Should fail on updating dlsn for an inprogress log segment"); - } catch (IllegalStateException ise) { - // expected - } - updatedCompletedLogSegment = Utils.ioResult(updater.updateLastRecord(completedLogSegment, goodRecord1)); - assertEquals(goodLastDLSN1, updatedCompletedLogSegment.getLastDLSN()); - assertEquals(goodRecord1.getTransactionId(), updatedCompletedLogSegment.getLastTxId()); - assertTrue(updatedCompletedLogSegment.isRecordLastPositioninThisSegment(goodRecord1)); - - segmentList = readLogSegments(ledgerPath); - assertEquals(2, segmentList.size()); - - readCompletedLogSegment = segmentList.get(1L); - assertNotNull(readCompletedLogSegment); - assertEquals(goodLastDLSN1, readCompletedLogSegment.getLastDLSN()); - assertEquals(goodRecord1.getTransactionId(), readCompletedLogSegment.getLastTxId()); - assertTrue(readCompletedLogSegment.isRecordLastPositioninThisSegment(goodRecord1)); - assertEquals(updatedCompletedLogSegment, readCompletedLogSegment); - assertEquals(completedLogSegment.getCompletionTime(), readCompletedLogSegment.getCompletionTime()); - assertEquals(completedLogSegment.getFirstTxId(), readCompletedLogSegment.getFirstTxId()); - assertEquals(completedLogSegment.getLogSegmentId(), readCompletedLogSegment.getLogSegmentId()); - assertEquals(completedLogSegment.getLogSegmentSequenceNumber(), - readCompletedLogSegment.getLogSegmentSequenceNumber()); - assertEquals(completedLogSegment.getRegionId(), readCompletedLogSegment.getRegionId()); - assertEquals(completedLogSegment.getZkPath(), readCompletedLogSegment.getZkPath()); - assertEquals(completedLogSegment.getZNodeName(), readCompletedLogSegment.getZNodeName()); - - readInprogressLogSegment = segmentList.get(2L); - assertNotNull(readInprogressLogSegment); - assertEquals(inprogressLogSegment, readInprogressLogSegment); - } - - @Test(timeout = 60000) - public void testChangeTruncationStatus() throws Exception { - String ledgerPath = "/ledgers2"; - zkc.get().create(ledgerPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - Map completedLogSegments = new HashMap(); - // Create 5 completed log segments - for (int i = 1; i <= 5; i++) { - LogSegmentMetadata segment = - DLMTestUtil.completedLogSegment(ledgerPath, i, (i - 1) * 100, i * 100 - 1, 100, i, 100, 0); - completedLogSegments.put(((long) i), segment); - LOG.info("Create completed segment {} : {}", segment.getZkPath(), segment); - segment.write(zkc); - } - - Map segmentList = readLogSegments(ledgerPath); - assertEquals(5, segmentList.size()); - - long segmentToModify = 1L; - - // Dryrun - MetadataUpdater dryrunUpdater = new DryrunLogSegmentMetadataStoreUpdater(conf, metadataStore); - Utils.ioResult(dryrunUpdater.setLogSegmentTruncated(segmentList.get(segmentToModify))); - - segmentList = readLogSegments(ledgerPath); - assertEquals(false, segmentList.get(segmentToModify).isTruncated()); - - // change truncation for the 1st log segment - MetadataUpdater updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(conf, metadataStore); - Utils.ioResult(updater.setLogSegmentTruncated(segmentList.get(segmentToModify))); - - segmentList = readLogSegments(ledgerPath); - assertEquals(true, segmentList.get(segmentToModify).isTruncated()); - assertEquals(false, segmentList.get(segmentToModify).isPartiallyTruncated()); - - updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(conf, metadataStore); - Utils.ioResult(updater.setLogSegmentActive(segmentList.get(segmentToModify))); - - segmentList = readLogSegments(ledgerPath); - assertEquals(false, segmentList.get(segmentToModify).isTruncated()); - assertEquals(false, segmentList.get(segmentToModify).isPartiallyTruncated()); - - updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(conf, metadataStore); - Utils.ioResult(updater.setLogSegmentPartiallyTruncated(segmentList.get(segmentToModify), - segmentList.get(segmentToModify).getFirstDLSN())); - - segmentList = readLogSegments(ledgerPath); - assertEquals(false, segmentList.get(segmentToModify).isTruncated()); - assertEquals(true, segmentList.get(segmentToModify).isPartiallyTruncated()); - - updater = LogSegmentMetadataStoreUpdater.createMetadataUpdater(conf, metadataStore); - Utils.ioResult(updater.setLogSegmentActive(segmentList.get(segmentToModify))); - - segmentList = readLogSegments(ledgerPath); - assertEquals(false, segmentList.get(segmentToModify).isTruncated()); - assertEquals(false, segmentList.get(segmentToModify).isPartiallyTruncated()); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java deleted file mode 100644 index e7141c4540e..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.namespace; - -import static org.apache.distributedlog.LocalDLMEmulator.DLOG_NAMESPACE; -import static org.junit.Assert.assertTrue; - -import java.net.URI; -import org.apache.distributedlog.BKDistributedLogNamespace; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.junit.Test; - -/** - * Test Namespace Builder. - */ -public class TestNamespaceBuilder extends TestDistributedLogBase { - - @Test(timeout = 60000, expected = NullPointerException.class) - public void testEmptyBuilder() throws Exception { - NamespaceBuilder.newBuilder().build(); - } - - @Test(timeout = 60000, expected = NullPointerException.class) - public void testMissingUri() throws Exception { - NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .build(); - } - - @Test(timeout = 60000, expected = NullPointerException.class) - public void testMissingSchemeInUri() throws Exception { - NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("/test")) - .build(); - } - - @Test(timeout = 60000, expected = IllegalArgumentException.class) - public void testInvalidSchemeInUri() throws Exception { - NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("dist://invalid/scheme/in/uri")) - .build(); - } - - @Test(timeout = 60000, expected = IllegalArgumentException.class) - public void testInvalidSchemeCorrectBackendInUri() throws Exception { - NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("dist-bk://invalid/scheme/in/uri")) - .build(); - } - - @Test(timeout = 60000, expected = IllegalArgumentException.class) - public void testUnknownBackendInUri() throws Exception { - NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("distributedlog-unknown://invalid/scheme/in/uri")) - .build(); - } - - @Test(timeout = 60000, expected = NullPointerException.class) - public void testNullStatsLogger() throws Exception { - NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("distributedlog-bk://localhost/distributedlog")) - .statsLogger(null) - .build(); - } - - @Test(timeout = 60000, expected = NullPointerException.class) - public void testNullClientId() throws Exception { - NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("distributedlog-bk://localhost/distributedlog")) - .clientId(null) - .build(); - } - - @Test(timeout = 60000) - public void testBuildBKDistributedLogNamespace() throws Exception { - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("distributedlog-bk://" + zkServers + DLOG_NAMESPACE + "/bknamespace")) - .build(); - try { - assertTrue("distributedlog-bk:// should build bookkeeper based distributedlog namespace", - namespace instanceof BKDistributedLogNamespace); - } finally { - namespace.close(); - } - } - - @Test(timeout = 60000) - public void testBuildWhenMissingBackendInUri() throws Exception { - Namespace namespace = NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(new URI("distributedlog://" + zkServers + DLOG_NAMESPACE + "/defaultnamespace")) - .build(); - try { - assertTrue("distributedlog:// should build bookkeeper based distributedlog namespace", - namespace instanceof BKDistributedLogNamespace); - } finally { - namespace.close(); - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestDNSResolver.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestDNSResolver.java deleted file mode 100644 index c1f4ec27e9a..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestDNSResolver.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.net; - -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.List; -import org.junit.Test; - - - -/** - * Test update for {@link DNSResolver}s. - */ -public class TestDNSResolver { - - private static final String host1 = "r1-w1rack1-1111-2222.distributedlog.io"; - private static final String host2 = "r2-w2rack2-3333-4444.distributedlog.io"; - - @Test(timeout = 20000) - public void testDNSResolverForRacks() { - DNSResolver dnsResolver = new DNSResolverForRacks(""); - - List ipList = new ArrayList(); - ipList.add("192.0.0.1"); - List racks = dnsResolver.resolve(ipList); - assertEquals(DNSResolverForRacks.DEFAULT_RACK, racks.get(0)); - - List unknownList = new ArrayList(); - unknownList.add("unknown"); - racks = dnsResolver.resolve(unknownList); - assertEquals(DNSResolverForRacks.DEFAULT_RACK, racks.get(0)); - - List r1List = new ArrayList(); - r1List.add(host1); - racks = dnsResolver.resolve(r1List); - assertEquals("/r1/w1rack1", racks.get(0)); - - List r2List = new ArrayList(); - r2List.add(host2); - racks = dnsResolver.resolve(r2List); - assertEquals("/r2/w2rack2", racks.get(0)); - } - - @Test(timeout = 20000) - public void testDNSResolverForRows() { - DNSResolver dnsResolver = new DNSResolverForRows(""); - - List ipList = new ArrayList(); - ipList.add("192.0.0.1"); - List rows = dnsResolver.resolve(ipList); - assertEquals(DNSResolverForRows.DEFAULT_ROW, rows.get(0)); - - List unknownList = new ArrayList(); - unknownList.add("unknown"); - rows = dnsResolver.resolve(unknownList); - assertEquals(DNSResolverForRows.DEFAULT_ROW, rows.get(0)); - - List r1List = new ArrayList(); - r1List.add(host1); - rows = dnsResolver.resolve(r1List); - assertEquals("/r1/w1", rows.get(0)); - - List r2List = new ArrayList(); - r2List.add(host2); - rows = dnsResolver.resolve(r2List); - assertEquals("/r2/w2", rows.get(0)); - } - - @Test(timeout = 20000) - public void testDNSResolverOverrides() { - DNSResolver dnsResolver = new DNSResolverForRacks("r1-w1rack1-1111-2222:r3;r2-w2rack2-3333-4444:r3"); - - List r1List = new ArrayList(); - r1List.add(host1); - List racks = dnsResolver.resolve(r1List); - assertEquals("/r3/w1rack1", racks.get(0)); - - List r2List = new ArrayList(); - r2List.add(host2); - racks = dnsResolver.resolve(r2List); - assertEquals("/r3/w2rack2", racks.get(0)); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestNetUtils.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestNetUtils.java deleted file mode 100644 index 30c31168459..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/net/TestNetUtils.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.net; - -import static org.junit.Assert.assertEquals; - -import java.util.List; -import org.apache.bookkeeper.net.DNSToSwitchMapping; -import org.junit.Test; - - -/** - * Test Cases of {@link NetUtils}. - */ -public class TestNetUtils { - - static class DNSResolverWithDefaultConstructor implements DNSToSwitchMapping { - - public DNSResolverWithDefaultConstructor() {} - - @Override - public List resolve(List list) { - return list; - } - - @Override - public void reloadCachedMappings() { - // no-op - } - } - - static class DNSResolverWithUnknownConstructor implements DNSToSwitchMapping { - - public DNSResolverWithUnknownConstructor(int var1, int var2, int var3) {} - - @Override - public List resolve(List list) { - return list; - } - - @Override - public void reloadCachedMappings() { - // no-op - } - } - - @Test(timeout = 20000) - public void testGetDNSResolverWithOverrides() throws Exception { - DNSToSwitchMapping dnsResolver = - NetUtils.getDNSResolver(DNSResolverForRacks.class, ""); - assertEquals("Should succeed to load " + DNSResolverForRacks.class, - dnsResolver.getClass(), DNSResolverForRacks.class); - } - - @Test(timeout = 20000) - public void testGetDNSResolverWithDefaultConstructor() throws Exception { - DNSToSwitchMapping dnsResolver = - NetUtils.getDNSResolver(DNSResolverWithDefaultConstructor.class, ""); - assertEquals("Should succeed to load " + DNSResolverWithDefaultConstructor.class, - dnsResolver.getClass(), DNSResolverWithDefaultConstructor.class); - } - - @Test(timeout = 20000, expected = RuntimeException.class) - public void testGetDNSResolverWithUnknownConstructor() throws Exception { - NetUtils.getDNSResolver(DNSResolverWithUnknownConstructor.class, ""); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/selector/TestLogRecordSelectors.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/selector/TestLogRecordSelectors.java deleted file mode 100644 index ee4f56fa7ce..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/selector/TestLogRecordSelectors.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.selector; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DLSN; -import org.junit.Test; - - -/** - * Test Case for {@link LogRecordSelector}s. - */ -public class TestLogRecordSelectors { - - @Test(timeout = 60000) - public void testFirstRecordSelector() { - FirstRecordSelector selectorIncludeControlRecord = - new FirstRecordSelector(true); - - for (int i = 0; i < 5; i++) { - selectorIncludeControlRecord.process( - DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(1L, i * 2, 0L), i * 2, true)); - selectorIncludeControlRecord.process( - DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(1L, i * 2 + 1, 0L), i * 2 + 1)); - } - assertEquals(new DLSN(1L, 0L, 0L), selectorIncludeControlRecord.result().getDlsn()); - - FirstRecordSelector selectorExcludeControlRecord = - new FirstRecordSelector(false); - - for (int i = 0; i < 5; i++) { - selectorExcludeControlRecord.process( - DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(1L, i * 2, 0L), i * 2, true)); - selectorExcludeControlRecord.process( - DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(1L, i * 2 + 1, 0L), i * 2 + 1)); - } - assertEquals(new DLSN(1L, 1L, 0L), selectorExcludeControlRecord.result().getDlsn()); - } - - @Test(timeout = 60000) - public void testLastRecordSelector() { - LastRecordSelector selector = new LastRecordSelector(); - - for (int i = 0; i < 10; i++) { - selector.process(DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(1L, i, 0L), i)); - } - assertEquals(new DLSN(1L, 9L, 0L), selector.result().getDlsn()); - } - - @Test(timeout = 60000) - public void testFirstDLSNNotLessThanSelector() { - DLSN dlsn = new DLSN(5L, 5L, 0L); - - FirstDLSNNotLessThanSelector largerSelector = - new FirstDLSNNotLessThanSelector(dlsn); - for (int i = 0; i < 10; i++) { - largerSelector.process(DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(4L, i, 0L), i)); - } - assertNull(largerSelector.result()); - - FirstDLSNNotLessThanSelector smallerSelector = - new FirstDLSNNotLessThanSelector(dlsn); - for (int i = 0; i < 10; i++) { - smallerSelector.process(DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(6L, i, 0L), i)); - } - assertEquals(new DLSN(6L, 0L, 0L), smallerSelector.result().getDlsn()); - - FirstDLSNNotLessThanSelector selector = - new FirstDLSNNotLessThanSelector(dlsn); - for (int i = 0; i < 10; i++) { - selector.process(DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(5L, i, 0L), i)); - } - assertEquals(dlsn, selector.result().getDlsn()); - } - - @Test(timeout = 60000) - public void testFirstTxIdNotLessThanSelector() { - long txId = 5 * 10 + 5; - - FirstTxIdNotLessThanSelector largerSelector = - new FirstTxIdNotLessThanSelector(txId); - for (int i = 0; i < 10; i++) { - largerSelector.process(DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(4L, i, 0L), 4 * 10 + i)); - } - assertEquals(49, largerSelector.result().getTransactionId()); - - FirstTxIdNotLessThanSelector smallerSelector = - new FirstTxIdNotLessThanSelector(txId); - for (int i = 0; i < 10; i++) { - smallerSelector.process(DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(6L, i, 0L), 6 * 10 + i)); - } - assertEquals(6 * 10, smallerSelector.result().getTransactionId()); - - FirstTxIdNotLessThanSelector selector = - new FirstTxIdNotLessThanSelector(txId); - for (int i = 0; i < 10; i++) { - selector.process(DLMTestUtil.getLogRecordWithDLSNInstance( - new DLSN(5L, i, 0L), 5 * 10 + i)); - } - assertEquals(txId, selector.result().getTransactionId()); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/tools/TestDistributedLogTool.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/tools/TestDistributedLogTool.java deleted file mode 100644 index 4aa6ac15768..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/tools/TestDistributedLogTool.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.tools; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.net.URI; -import org.apache.bookkeeper.client.BKException.BKNoSuchLedgerExistsOnMetadataServerException; -import org.apache.bookkeeper.common.util.ReflectionUtils; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.LocalDLMEmulator; -import org.apache.distributedlog.LogRecordWithDLSN; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.LogReader; -import org.apache.distributedlog.exceptions.ZKException; -import org.apache.distributedlog.tools.DistributedLogTool.CreateCommand; -import org.apache.distributedlog.tools.DistributedLogTool.DeleteAllocatorPoolCommand; -import org.apache.distributedlog.tools.DistributedLogTool.DeleteCommand; -import org.apache.distributedlog.tools.DistributedLogTool.DumpCommand; -import org.apache.distributedlog.tools.DistributedLogTool.InspectCommand; -import org.apache.distributedlog.tools.DistributedLogTool.ListCommand; -import org.apache.distributedlog.tools.DistributedLogTool.ReadEntriesCommand; -import org.apache.distributedlog.tools.DistributedLogTool.ReadLastConfirmedCommand; -import org.apache.distributedlog.tools.DistributedLogTool.ShowCommand; -import org.apache.distributedlog.tools.DistributedLogTool.TruncateCommand; -import org.apache.distributedlog.tools.DistributedLogTool.TruncateStreamCommand; -import org.apache.zookeeper.KeeperException; -import org.junit.BeforeClass; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Test Case for {@link DistributedLogTool}s. - */ -public class TestDistributedLogTool extends TestDistributedLogBase { - - static final Logger LOG = LoggerFactory.getLogger(TestDistributedLogTool.class); - - private static final String defaultLedgerPath = LocalDLMEmulator.getBkLedgerPath(); - private static final String defaultPath = "/test/namespace"; - private static final String defaultHost = "127.0.0.1"; - private static final String defaultPrivilegedZkAclId = "NathanielP"; - static URI defaultUri = null; - - static final String ADMIN_TOOL = org.apache.distributedlog.admin.DistributedLogAdmin.class.getName(); - - @BeforeClass - public static void setupDefaults() throws Exception { - defaultUri = DLMTestUtil.createDLMURI(zkPort, defaultPath); - DistributedLogManager dlm = DLMTestUtil.createNewDLM("DefaultStream", conf, defaultUri); - bindStream(defaultUri, defaultLedgerPath, defaultHost); - DLMTestUtil.generateCompletedLogSegments(dlm, conf, 3, 8192); - dlm.close(); - } - - private static int runTool(String[] args) throws Exception { - Tool tool = ReflectionUtils.newInstance(args[0], Tool.class); - String[] newArgs = new String[args.length - 1]; - System.arraycopy(args, 1, newArgs, 0, newArgs.length); - int rc = tool.run(newArgs); - assertTrue(0 == rc); - return rc; - } - - static void bindStream(URI uri, String ledgerPath, String zkHosts) throws Exception { - String[] args = new String[] { ADMIN_TOOL, - "bind", - "-c", - "-l", ledgerPath, - "-s", zkHosts, - "-f", uri.toString() }; - runTool(args); - } - - static void createStream(URI uri, String prefix, String expression, String zkAclId) throws Exception { - CreateCommand cmd = new CreateCommand(); - cmd.setUri(defaultUri); - cmd.setPrefix(prefix); - cmd.setExpression(expression); - cmd.setForce(true); - cmd.setZkAclId(zkAclId); - assertEquals(0, cmd.runCmd()); - } - - void deleteStream(URI uri, String stream) throws Exception { - DeleteCommand cmd = new DeleteCommand(); - cmd.setUri(defaultUri); - cmd.setStreamName(stream); - assertEquals(0, cmd.runCmd()); - } - - void list(URI uri) throws Exception { - ListCommand cmd = new ListCommand(); - cmd.setUri(defaultUri); - assertEquals(0, cmd.runCmd()); - } - - @Test(timeout = 60000) - public void testToolCreate() throws Exception { - createStream(defaultUri, "0", "TestPrefix", null); - } - - @Test(timeout = 60000) - public void testToolCreateZkAclId() throws Exception { - createStream(defaultUri, "0", "CreateAclStream", defaultPrivilegedZkAclId); - try { - DistributedLogManager dlm = DLMTestUtil.createNewDLM("0CreateAclStream", conf, defaultUri); - DLMTestUtil.generateCompletedLogSegments(dlm, conf, 3, 1000); - dlm.close(); - } catch (ZKException ex) { - assertEquals(KeeperException.Code.NOAUTH, ex.getKeeperExceptionCode()); - } - } - - @Test(timeout = 60000) - public void testToolDelete() throws Exception { - createStream(defaultUri, "1", "TestPrefix", null); - deleteStream(defaultUri, "1TestPrefix"); - } - - @Test(timeout = 60000) - public void testToolDeleteAllocPool() throws Exception { - try { - DeleteAllocatorPoolCommand cmd = new DeleteAllocatorPoolCommand(); - cmd.setUri(defaultUri); - assertEquals(0, cmd.runCmd()); - fail("should have failed"); - } catch (org.apache.zookeeper.KeeperException.NoNodeException ex) { - } - } - - @Test(timeout = 60000) - public void testToolList() throws Exception { - list(defaultUri); - } - - @Test(timeout = 60000) - public void testToolDump() throws Exception { - DumpCommand cmd = new DumpCommand(); - cmd.setUri(defaultUri); - cmd.setStreamName("DefaultStream"); - cmd.setFromTxnId(0L); - assertEquals(0, cmd.runCmd()); - } - - @Test(timeout = 60000) - public void testToolShow() throws Exception { - ShowCommand cmd = new ShowCommand(); - cmd.setUri(defaultUri); - cmd.setStreamName("DefaultStream"); - assertEquals(0, cmd.runCmd()); - } - @Test(timeout = 60000) - public void testToolTruncate() throws Exception { - DistributedLogManager dlm = DLMTestUtil.createNewDLM("TruncateStream", conf, defaultUri); - DLMTestUtil.generateCompletedLogSegments(dlm, conf, 3, 1000); - dlm.close(); - - TruncateCommand cmd = new TruncateCommand(); - cmd.setUri(defaultUri); - cmd.setFilter("TruncateStream"); - cmd.setForce(true); - assertEquals(0, cmd.runCmd()); - } - - @Test(timeout = 60000) - public void testToolInspect() throws Exception { - InspectCommand cmd = new InspectCommand(); - cmd.setUri(defaultUri); - cmd.setForce(true); - assertEquals(0, cmd.runCmd()); - } - - @Test(timeout = 60000) - public void testToolReadLastConfirmed() throws Exception { - ReadLastConfirmedCommand cmd = new ReadLastConfirmedCommand(); - cmd.setUri(defaultUri); - cmd.setLedgerId(99999999); - - // Too hard to predict ledger entry id. Settle for basicaly - // correct functionality. - try { - cmd.runCmd(); - } catch (BKNoSuchLedgerExistsOnMetadataServerException ex) { - } - } - - @Test(timeout = 60000) - public void testToolReadEntriesCommand() throws Exception { - ReadEntriesCommand cmd = new ReadEntriesCommand(); - cmd.setUri(defaultUri); - cmd.setLedgerId(99999999); - try { - cmd.runCmd(); - } catch (BKNoSuchLedgerExistsOnMetadataServerException ex) { - } - } - - @Test(timeout = 60000) - public void testToolTruncateStream() throws Exception { - DistributedLogConfiguration confLocal = new DistributedLogConfiguration(); - confLocal.addConfiguration(conf); - confLocal.setLogSegmentCacheEnabled(false); - DistributedLogManager dlm = DLMTestUtil.createNewDLM("testToolTruncateStream", confLocal, defaultUri); - DLMTestUtil.generateCompletedLogSegments(dlm, confLocal, 3, 1000); - - DLSN dlsn = new DLSN(2, 1, 0); - TruncateStreamCommand cmd = new TruncateStreamCommand(); - cmd.setDlsn(dlsn); - cmd.setUri(defaultUri); - cmd.setStreamName("testToolTruncateStream"); - cmd.setForce(true); - - assertEquals(0, cmd.runCmd()); - - LogReader reader = dlm.getInputStream(0); - LogRecordWithDLSN record = reader.readNext(false); - assertEquals(dlsn, record.getDlsn()); - - reader.close(); - dlm.close(); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestConfUtils.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestConfUtils.java deleted file mode 100644 index 366d561eb62..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestConfUtils.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.util; - -import static org.junit.Assert.assertEquals; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.junit.Test; - - -/** - * Test Case for {@link Configuration}s. - */ -public class TestConfUtils { - - @Test(timeout = 60000) - public void testLoadConfiguration() { - Configuration conf1 = new CompositeConfiguration(); - conf1.setProperty("key1", "value1"); - conf1.setProperty("key2", "value2"); - conf1.setProperty("key3", "value3"); - - Configuration conf2 = new CompositeConfiguration(); - conf2.setProperty("bkc.key1", "bkc.value1"); - conf2.setProperty("bkc.key4", "bkc.value4"); - - assertEquals("value1", conf1.getString("key1")); - assertEquals("value2", conf1.getString("key2")); - assertEquals("value3", conf1.getString("key3")); - assertEquals(null, conf1.getString("key4")); - - ConfUtils.loadConfiguration(conf1, conf2, "bkc."); - - assertEquals("bkc.value1", conf1.getString("key1")); - assertEquals("value2", conf1.getString("key2")); - assertEquals("value3", conf1.getString("key3")); - assertEquals("bkc.value4", conf1.getString("key4")); - assertEquals(null, conf1.getString("bkc.key1")); - assertEquals(null, conf1.getString("bkc.key4")); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestDLUtils.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestDLUtils.java deleted file mode 100644 index 855935ce754..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestDLUtils.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.util; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.distributedlog.util.DLUtils.validateAndNormalizeName; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import com.google.common.collect.Lists; -import java.util.List; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.LogSegmentMetadata; -import org.apache.distributedlog.LogSegmentMetadata.LogSegmentMetadataVersion; -import org.apache.distributedlog.exceptions.InvalidStreamNameException; -import org.apache.distributedlog.exceptions.UnexpectedException; -import org.junit.Test; - - - - -/** - * Test Case for {@link DLUtils}. - */ -public class TestDLUtils { - - private static LogSegmentMetadata completedLogSegment( - long logSegmentSequenceNumber, - long fromTxnId, - long toTxnId) { - return completedLogSegment( - logSegmentSequenceNumber, - fromTxnId, - toTxnId, - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - } - - private static LogSegmentMetadata completedLogSegment( - long logSegmentSequenceNumber, - long fromTxnId, - long toTxnId, - int version) { - return DLMTestUtil.completedLogSegment( - "/logsegment/" + fromTxnId, - fromTxnId, - fromTxnId, - toTxnId, - 100, - logSegmentSequenceNumber, - 999L, - 0L, - version); - } - - private static LogSegmentMetadata inprogressLogSegment( - long logSegmentSequenceNumber, long firstTxId) { - return inprogressLogSegment( - logSegmentSequenceNumber, - firstTxId, - LogSegmentMetadata.LEDGER_METADATA_CURRENT_LAYOUT_VERSION); - } - - private static LogSegmentMetadata inprogressLogSegment( - long logSegmentSequenceNumber, long firstTxId, int version) { - return DLMTestUtil.inprogressLogSegment( - "/logsegment/" + firstTxId, - firstTxId, - firstTxId, - logSegmentSequenceNumber, - version); - } - - @Test(timeout = 60000) - public void testFindLogSegmentNotLessThanTxnId() throws Exception { - long txnId = 999L; - // empty list - List emptyList = Lists.newArrayList(); - assertEquals(-1, DLUtils.findLogSegmentNotLessThanTxnId(emptyList, txnId)); - - // list that all segment's txn id is larger than txn-id-to-search - List list1 = Lists.newArrayList( - completedLogSegment(1L, 1000L, 2000L)); - assertEquals(-1, DLUtils.findLogSegmentNotLessThanTxnId(list1, txnId)); - - List list2 = Lists.newArrayList( - inprogressLogSegment(1L, 1000L)); - assertEquals(-1, DLUtils.findLogSegmentNotLessThanTxnId(list2, txnId)); - - // the first log segment whose first txn id is less than txn-id-to-search - List list3 = Lists.newArrayList( - completedLogSegment(1L, 0L, 99L), - completedLogSegment(2L, 1000L, 2000L) - ); - assertEquals(1, DLUtils.findLogSegmentNotLessThanTxnId(list3, txnId)); - - List list4 = Lists.newArrayList( - completedLogSegment(1L, 0L, 990L), - completedLogSegment(2L, 1000L, 2000L) - ); - assertEquals(1, DLUtils.findLogSegmentNotLessThanTxnId(list4, txnId)); - - List list5 = Lists.newArrayList( - inprogressLogSegment(1L, 0L), - inprogressLogSegment(2L, 1000L) - ); - assertEquals(0, DLUtils.findLogSegmentNotLessThanTxnId(list5, txnId)); - - // list that all segment's txn id is less than txn-id-to-search - List list6_0 = Lists.newArrayList( - completedLogSegment(1L, 100L, 200L)); - assertEquals(0, DLUtils.findLogSegmentNotLessThanTxnId(list6_0, txnId)); - - List list6_1 = Lists.newArrayList( - completedLogSegment(1L, 100L, 199L), - completedLogSegment(2L, 200L, 299L)); - assertEquals(1, DLUtils.findLogSegmentNotLessThanTxnId(list6_1, txnId)); - - List list7 = Lists.newArrayList( - inprogressLogSegment(1L, 100L)); - assertEquals(0, DLUtils.findLogSegmentNotLessThanTxnId(list7, txnId)); - - // list that first segment's first txn id equals to txn-id-to-search - List list8 = Lists.newArrayList( - completedLogSegment(1L, 999L, 2000L)); - assertEquals(0, DLUtils.findLogSegmentNotLessThanTxnId(list8, txnId)); - - List list9 = Lists.newArrayList( - inprogressLogSegment(1L, 999L)); - assertEquals(0, DLUtils.findLogSegmentNotLessThanTxnId(list9, txnId)); - - List list10 = Lists.newArrayList( - completedLogSegment(1L, 0L, 999L), - completedLogSegment(2L, 999L, 2000L)); - assertEquals(0, DLUtils.findLogSegmentNotLessThanTxnId(list10, txnId)); - - List list11 = Lists.newArrayList( - completedLogSegment(1L, 0L, 99L), - completedLogSegment(2L, 999L, 2000L)); - assertEquals(1, DLUtils.findLogSegmentNotLessThanTxnId(list11, txnId)); - - List list12 = Lists.newArrayList( - inprogressLogSegment(1L, 0L), - inprogressLogSegment(2L, 999L)); - assertEquals(1, DLUtils.findLogSegmentNotLessThanTxnId(list12, txnId)); - } - - @Test(timeout = 60000) - public void testNextLogSegmentSequenceNumber() throws Exception { - List v1List = Lists.newArrayList( - completedLogSegment(2L, 100L, 199L, LogSegmentMetadataVersion.VERSION_V1_ORIGINAL.value), - completedLogSegment(1L, 0L, 99L, LogSegmentMetadataVersion.VERSION_V1_ORIGINAL.value)); - assertNull(DLUtils.nextLogSegmentSequenceNumber(v1List)); - - List afterV1List = Lists.newArrayList( - completedLogSegment(2L, 100L, 199L), - completedLogSegment(1L, 0L, 99L)); - assertEquals((Long) 3L, DLUtils.nextLogSegmentSequenceNumber(afterV1List)); - - List mixList1 = Lists.newArrayList( - completedLogSegment(2L, 100L, 199L, LogSegmentMetadataVersion.VERSION_V1_ORIGINAL.value), - completedLogSegment(1L, 0L, 99L)); - assertEquals((Long) 3L, DLUtils.nextLogSegmentSequenceNumber(mixList1)); - - List mixList2 = Lists.newArrayList( - completedLogSegment(2L, 100L, 199L), - completedLogSegment(1L, 0L, 99L, LogSegmentMetadataVersion.VERSION_V1_ORIGINAL.value)); - assertEquals((Long) 3L, DLUtils.nextLogSegmentSequenceNumber(mixList2)); - } - - @Test(timeout = 60000, expected = UnexpectedException.class) - public void testUnexpectedExceptionOnComputeStartSequenceId() throws Exception { - List segments = Lists.newArrayList( - inprogressLogSegment(3L, 201L), - inprogressLogSegment(2L, 101L), - completedLogSegment(1L, 1L, 100L).mutator().setStartSequenceId(1L).build() - ); - DLUtils.computeStartSequenceId(segments, segments.get(0)); - } - - @Test(timeout = 60000) - public void testComputeStartSequenceIdOnEmptyList() throws Exception { - List emptyList = Lists.newArrayList(); - assertEquals(0L, DLUtils.computeStartSequenceId(emptyList, inprogressLogSegment(1L, 1L))); - } - - @Test(timeout = 60000) - public void testComputeStartSequenceIdOnLowerSequenceNumberSegment() throws Exception { - List segments = Lists.newArrayList( - completedLogSegment(3L, 201L, 300L).mutator().setStartSequenceId(201L).build(), - completedLogSegment(2L, 101L, 200L).mutator().setStartSequenceId(101L).build() - ); - assertEquals(0L, DLUtils.computeStartSequenceId(segments, inprogressLogSegment(1L, 1L))); - } - - @Test(timeout = 60000) - public void testComputeStartSequenceIdOnHigherSequenceNumberSegment() throws Exception { - List segments = Lists.newArrayList( - completedLogSegment(3L, 201L, 300L).mutator().setStartSequenceId(201L).build(), - completedLogSegment(2L, 101L, 200L).mutator().setStartSequenceId(101L).build() - ); - assertEquals(0L, DLUtils.computeStartSequenceId(segments, inprogressLogSegment(5L, 401L))); - } - - @Test(timeout = 60000) - public void testComputeStartSequenceId() throws Exception { - List segments = Lists.newArrayList( - completedLogSegment(3L, 201L, 300L).mutator() - .setStartSequenceId(201L).setRecordCount(100).build(), - completedLogSegment(2L, 101L, 200L).mutator() - .setStartSequenceId(101L).setRecordCount(100).build() - ); - assertEquals(301L, DLUtils.computeStartSequenceId(segments, inprogressLogSegment(4L, 301L))); - } - - @Test(timeout = 60000) - public void testSerDeLogSegmentSequenceNumber() throws Exception { - long sn = 123456L; - byte[] snData = Long.toString(sn).getBytes(UTF_8); - assertEquals("Deserialization should succeed", - sn, DLUtils.deserializeLogSegmentSequenceNumber(snData)); - assertArrayEquals("Serialization should succeed", - snData, DLUtils.serializeLogSegmentSequenceNumber(sn)); - } - - @Test(timeout = 60000, expected = NumberFormatException.class) - public void testDeserilizeInvalidLSSN() throws Exception { - byte[] corruptedData = "corrupted-lssn".getBytes(UTF_8); - DLUtils.deserializeLogSegmentSequenceNumber(corruptedData); - } - - @Test(timeout = 60000) - public void testSerDeLogRecordTxnId() throws Exception { - long txnId = 123456L; - byte[] txnData = Long.toString(txnId).getBytes(UTF_8); - assertEquals("Deserialization should succeed", - txnId, DLUtils.deserializeTransactionId(txnData)); - assertArrayEquals("Serialization should succeed", - txnData, DLUtils.serializeTransactionId(txnId)); - } - - @Test(timeout = 60000, expected = NumberFormatException.class) - public void testDeserilizeInvalidLogRecordTxnId() throws Exception { - byte[] corruptedData = "corrupted-txn-id".getBytes(UTF_8); - DLUtils.deserializeTransactionId(corruptedData); - } - - @Test(timeout = 60000) - public void testSerDeLedgerId() throws Exception { - long ledgerId = 123456L; - byte[] ledgerIdData = Long.toString(ledgerId).getBytes(UTF_8); - assertEquals("Deserialization should succeed", - ledgerId, DLUtils.bytes2LogSegmentId(ledgerIdData)); - assertArrayEquals("Serialization should succeed", - ledgerIdData, DLUtils.logSegmentId2Bytes(ledgerId)); - } - - @Test(timeout = 60000, expected = NumberFormatException.class) - public void testDeserializeInvalidLedgerId() throws Exception { - byte[] corruptedData = "corrupted-ledger-id".getBytes(UTF_8); - DLUtils.bytes2LogSegmentId(corruptedData); - } - - @Test(timeout = 10000) - public void testValidateLogName() throws Exception { - String logName = "test-validate-log-name"; - validateAndNormalizeName(logName); - } - - @Test(timeout = 10000, expected = InvalidStreamNameException.class) - public void testValidateBadLogName0() throws Exception { - String logName = " test-bad-log-name"; - validateAndNormalizeName(logName); - } - - @Test(timeout = 10000, expected = InvalidStreamNameException.class) - public void testValidateBadLogName1() throws Exception { - String logName = "test-bad-log-name/"; - validateAndNormalizeName(logName); - } - - @Test(timeout = 10000, expected = InvalidStreamNameException.class) - public void testValidateBadLogName2() throws Exception { - String logName = "../test-bad-log-name/"; - validateAndNormalizeName(logName); - } - - @Test(timeout = 10000) - public void testValidateSameStreamPath() throws Exception { - String logName1 = "/test-resolve-log"; - String logName2 = "test-resolve-log"; - validateAndNormalizeName(logName1); - validateAndNormalizeName(logName2); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestPermitManager.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestPermitManager.java deleted file mode 100644 index f36c30c3352..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestPermitManager.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.util; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.apache.distributedlog.common.util.PermitManager; -import org.apache.distributedlog.zk.LimitedPermitManager; -import org.junit.Test; - - - - -/** - * Test Case for {@link PermitManager}. - */ -public class TestPermitManager { - - @Test(timeout = 60000) - public void testUnlimitedPermitManager() { - PermitManager pm = PermitManager.UNLIMITED_PERMIT_MANAGER; - List permits = new ArrayList(); - for (int i = 0; i < 10; i++) { - permits.add(pm.acquirePermit()); - } - for (int i = 0; i < 10; i++) { - assertTrue(permits.get(i).isAllowed()); - pm.releasePermit(permits.get(i)); - } - PermitManager.Permit permit = pm.acquirePermit(); - pm.disallowObtainPermits(permit); - pm.releasePermit(permit); - - for (int i = 0; i < 10; i++) { - permits.add(pm.acquirePermit()); - } - for (int i = 0; i < 10; i++) { - assertTrue(permits.get(i).isAllowed()); - pm.releasePermit(permits.get(i)); - } - } - - @Test(timeout = 60000) - public void testLimitedPermitManager() { - ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); - PermitManager pm = new LimitedPermitManager(1, 0, TimeUnit.SECONDS, executorService); - PermitManager.Permit permit1 = pm.acquirePermit(); - PermitManager.Permit permit2 = pm.acquirePermit(); - assertTrue(permit1.isAllowed()); - assertFalse(permit2.isAllowed()); - pm.releasePermit(permit2); - PermitManager.Permit permit3 = pm.acquirePermit(); - assertFalse(permit3.isAllowed()); - pm.releasePermit(permit3); - pm.releasePermit(permit1); - PermitManager.Permit permit4 = pm.acquirePermit(); - assertTrue(permit4.isAllowed()); - pm.releasePermit(permit4); - - PermitManager pm2 = new LimitedPermitManager(2, 0, TimeUnit.SECONDS, executorService); - - PermitManager.Permit permit5 = pm2.acquirePermit(); - PermitManager.Permit permit6 = pm2.acquirePermit(); - assertTrue(permit5.isAllowed()); - assertTrue(permit6.isAllowed()); - assertTrue(pm2.disallowObtainPermits(permit5)); - assertFalse(pm2.disallowObtainPermits(permit6)); - pm2.releasePermit(permit5); - pm2.releasePermit(permit6); - PermitManager.Permit permit7 = pm2.acquirePermit(); - assertFalse(permit7.isAllowed()); - pm2.releasePermit(permit7); - pm2.allowObtainPermits(); - PermitManager.Permit permit8 = pm2.acquirePermit(); - assertTrue(permit8.isAllowed()); - pm2.releasePermit(permit2); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestTimeSequencer.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestTimeSequencer.java deleted file mode 100644 index 5efd9997ca7..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestTimeSequencer.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - - -/** - * Test Case for {@link TimeSequencer}. - */ -public class TestTimeSequencer { - - @Test(timeout = 60000) - public void testNonDecreasingId() { - TimeSequencer sequencer = new TimeSequencer(); - long lastId = System.currentTimeMillis() + 3600000; - sequencer.setLastId(lastId); - for (int i = 0; i < 10; i++) { - assertEquals(lastId, sequencer.nextId()); - } - sequencer.setLastId(15); - long prevId = 15; - for (int i = 0; i < 10; i++) { - long newId = sequencer.nextId(); - assertTrue("id should not decrease", - newId >= prevId); - prevId = newId; - } - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestUtils.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestUtils.java deleted file mode 100644 index 6ae197acb54..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/util/TestUtils.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.util; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.util.Optional; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.TestZooKeeperClientBuilder; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.zookeeper.AsyncCallback; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.ZooDefs; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Test Utils. - */ -public class TestUtils extends ZooKeeperClusterTestCase { - - private static final int sessionTimeoutMs = 30000; - - private ZooKeeperClient zkc; - - @Before - public void setup() throws Exception { - zkc = TestZooKeeperClientBuilder.newBuilder() - .name("zkc") - .uri(DLMTestUtil.createDLMURI(zkPort, "/")) - .sessionTimeoutMs(sessionTimeoutMs) - .build(); - } - - @After - public void teardown() throws Exception { - zkc.close(); - } - - @Test(timeout = 60000) - public void testZkAsyncCreateFulPathOptimisticRecursive() throws Exception { - String path1 = "/a/b/c/d"; - Optional parentPathShouldNotCreate = Optional.empty(); - final CountDownLatch doneLatch1 = new CountDownLatch(1); - Utils.zkAsyncCreateFullPathOptimisticRecursive(zkc, path1, parentPathShouldNotCreate, - new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, - new AsyncCallback.StringCallback() { - @Override - public void processResult(int rc, String path, Object ctx, String name) { - doneLatch1.countDown(); - } - }, null); - doneLatch1.await(); - assertNotNull(zkc.get().exists(path1, false)); - - String path2 = "/a/b/c/d/e/f/g"; - parentPathShouldNotCreate = Optional.of("/a/b/c/d/e"); - final CountDownLatch doneLatch2 = new CountDownLatch(1); - Utils.zkAsyncCreateFullPathOptimisticRecursive(zkc, path2, parentPathShouldNotCreate, - new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, - new AsyncCallback.StringCallback() { - @Override - public void processResult(int rc, String path, Object ctx, String name) { - doneLatch2.countDown(); - } - }, null); - doneLatch2.await(); - assertNull(zkc.get().exists("/a/b/c/d/e", false)); - assertNull(zkc.get().exists("/a/b/c/d/e/f", false)); - assertNull(zkc.get().exists("/a/b/c/d/e/f/g", false)); - - parentPathShouldNotCreate = Optional.of("/a/b"); - final CountDownLatch doneLatch3 = new CountDownLatch(1); - Utils.zkAsyncCreateFullPathOptimisticRecursive(zkc, path2, parentPathShouldNotCreate, - new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, - new AsyncCallback.StringCallback() { - @Override - public void processResult(int rc, String path, Object ctx, String name) { - doneLatch3.countDown(); - } - }, null); - doneLatch3.await(); - assertNotNull(zkc.get().exists(path2, false)); - } - - @Test(timeout = 60000) - public void testZkGetData() throws Exception { - String path1 = "/zk-get-data/non-existent-path"; - Versioned data = Utils.ioResult(Utils.zkGetData(zkc.get(), path1, false)); - assertNull("No data should return from non-existent-path", data.getValue()); - assertNull("No version should return from non-existent-path", data.getVersion()); - - String path2 = "/zk-get-data/path2"; - byte[] rawData = "test-data".getBytes(UTF_8); - Utils.ioResult(Utils.zkAsyncCreateFullPathOptimistic(zkc, path2, rawData, - zkc.getDefaultACL(), CreateMode.PERSISTENT)); - data = Utils.ioResult(Utils.zkGetData(zkc.get(), path2, false)); - assertArrayEquals("Data should return as written", - rawData, data.getValue()); - assertEquals("Version should be zero", - 0L, ((LongVersion) data.getVersion()).getLongVersion()); - } - - @Test(timeout = 60000) - public void testGetParent() throws Exception { - String path1 = null; - assertNull("parent of a null path is null", Utils.getParent(path1)); - - String path2 = ""; - assertNull("parent of an empty string is null", Utils.getParent(path2)); - - String path3 = "abcdef"; - assertNull("parent of a string with no / is null", Utils.getParent(path3)); - - String path4 = "/test/test2"; - assertEquals("parent of a /test/test2 is /test", "/test", Utils.getParent(path4)); - - String path5 = "/test/test2/"; - assertEquals("parent of a " + path5 + " is /test", "/test", Utils.getParent(path5)); - - String path6 = "/test"; - assertEquals("parent of " + path6 + " is /", "/", Utils.getParent(path6)); - - String path7 = "//"; - assertEquals("parent of " + path7 + " is /", "/", Utils.getParent(path7)); - - String path8 = "/"; - assertNull("parent of " + path8 + " is null", Utils.getParent(path8)); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKTransaction.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKTransaction.java deleted file mode 100644 index 0ec9d40e19c..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKTransaction.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.zk; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - -import java.util.concurrent.CountDownLatch; -import javax.annotation.Nullable; -import org.apache.distributedlog.ZooKeeperClient; -import org.apache.distributedlog.exceptions.DLIllegalStateException; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.Op; -import org.apache.zookeeper.OpResult; -import org.junit.Test; - - - - -/** - * Test Case for zookeeper transaction. - */ -public class TestZKTransaction { - - static class CountDownZKOp extends ZKOp { - - final CountDownLatch commitLatch; - final CountDownLatch abortLatch; - - CountDownZKOp(CountDownLatch commitLatch, - CountDownLatch abortLatch) { - super(mock(Op.class)); - this.commitLatch = commitLatch; - this.abortLatch = abortLatch; - } - - @Override - protected void commitOpResult(OpResult opResult) { - this.commitLatch.countDown(); - } - - @Override - protected void abortOpResult(Throwable t, @Nullable OpResult opResult) { - this.abortLatch.countDown(); - } - } - - @Test(timeout = 60000) - public void testProcessNullResults() throws Exception { - ZooKeeperClient zkc = mock(ZooKeeperClient.class); - ZKTransaction transaction = new ZKTransaction(zkc); - int numOps = 3; - final CountDownLatch commitLatch = new CountDownLatch(numOps); - final CountDownLatch abortLatch = new CountDownLatch(numOps); - for (int i = 0; i < numOps; i++) { - transaction.addOp(new CountDownZKOp(commitLatch, abortLatch)); - } - transaction.processResult( - KeeperException.Code.CONNECTIONLOSS.intValue(), - "test-path", - null, - null); - abortLatch.await(); - assertEquals(0, abortLatch.getCount()); - assertEquals(numOps, commitLatch.getCount()); - } - - @Test(timeout = 60000) - public void testAbortTransaction() throws Exception { - ZooKeeperClient zkc = mock(ZooKeeperClient.class); - ZKTransaction transaction = new ZKTransaction(zkc); - int numOps = 3; - final CountDownLatch commitLatch = new CountDownLatch(numOps); - final CountDownLatch abortLatch = new CountDownLatch(numOps); - for (int i = 0; i < numOps; i++) { - transaction.addOp(new CountDownZKOp(commitLatch, abortLatch)); - } - transaction.abort(new DLIllegalStateException("Illegal State")); - abortLatch.await(); - assertEquals(0, abortLatch.getCount()); - assertEquals(numOps, commitLatch.getCount()); - } - -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKVersionedSetOp.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKVersionedSetOp.java deleted file mode 100644 index 52779387df6..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKVersionedSetOp.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.zk; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.versioning.Version; -import org.apache.distributedlog.util.Transaction; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.Op; -import org.apache.zookeeper.OpResult; -import org.junit.Test; - - - - -/** - * Test Case for versioned set operation. - */ -public class TestZKVersionedSetOp { - - @Test(timeout = 60000) - public void testAbortNullOpResult() throws Exception { - final AtomicReference exception = - new AtomicReference(); - final CountDownLatch latch = new CountDownLatch(1); - ZKVersionedSetOp versionedSetOp = - new ZKVersionedSetOp(mock(Op.class), new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - // no-op - } - - @Override - public void onAbort(Throwable t) { - exception.set(t); - latch.countDown(); - } - }); - KeeperException ke = KeeperException.create(KeeperException.Code.SESSIONEXPIRED); - versionedSetOp.abortOpResult(ke, null); - latch.await(); - assertTrue(ke == exception.get()); - } - - @Test(timeout = 60000) - public void testAbortOpResult() throws Exception { - final AtomicReference exception = - new AtomicReference(); - final CountDownLatch latch = new CountDownLatch(1); - ZKVersionedSetOp versionedSetOp = - new ZKVersionedSetOp(mock(Op.class), new Transaction.OpListener() { - @Override - public void onCommit(Version r) { - // no-op - } - - @Override - public void onAbort(Throwable t) { - exception.set(t); - latch.countDown(); - } - }); - KeeperException ke = KeeperException.create(KeeperException.Code.SESSIONEXPIRED); - OpResult opResult = new OpResult.ErrorResult(KeeperException.Code.NONODE.intValue()); - versionedSetOp.abortOpResult(ke, opResult); - latch.await(); - assertTrue(exception.get() instanceof KeeperException.NoNodeException); - } -} diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKWatcherManager.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKWatcherManager.java deleted file mode 100644 index 64c2ac15560..00000000000 --- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/zk/TestZKWatcherManager.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog.zk; - -import static org.junit.Assert.assertEquals; - -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher; -import org.junit.Test; - - - - -/** - * Test Case for {@link ZKWatcherManager}. - */ -public class TestZKWatcherManager { - - @Test(timeout = 60000) - public void testRegisterUnregisterWatcher() throws Exception { - ZKWatcherManager watcherManager = ZKWatcherManager.newBuilder() - .name("test-register-unregister-watcher") - .zkc(null) - .statsLogger(NullStatsLogger.INSTANCE) - .build(); - String path = "/test-register-unregister-watcher"; - final List events = new LinkedList(); - final CountDownLatch latch = new CountDownLatch(2); - Watcher watcher = new Watcher() { - @Override - public void process(WatchedEvent event) { - events.add(event); - latch.countDown(); - } - }; - watcherManager.registerChildWatcher(path, watcher); - - // fire the event - WatchedEvent event0 = new WatchedEvent( - Watcher.Event.EventType.NodeCreated, - Watcher.Event.KeeperState.SyncConnected, - path); - WatchedEvent event1 = new WatchedEvent( - Watcher.Event.EventType.None, - Watcher.Event.KeeperState.SyncConnected, - path); - WatchedEvent event2 = new WatchedEvent( - Watcher.Event.EventType.NodeChildrenChanged, - Watcher.Event.KeeperState.SyncConnected, - path); - watcher.process(event1); - watcher.process(event2); - - latch.await(); - - assertEquals(2, events.size()); - assertEquals(event1, events.get(0)); - assertEquals(event2, events.get(1)); - - // unregister watcher - watcherManager.unregisterChildWatcher(path, watcher, true); - // unregister gauges - watcherManager.unregisterGauges(); - assertEquals(0, watcherManager.childWatches.size()); - } -} diff --git a/stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFSBase.java b/stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFSBase.java deleted file mode 100644 index 1c67d366337..00000000000 --- a/stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFSBase.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.distributedlog.fs; - -import java.net.URI; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.Path; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.rules.TestName; - -/** - * Integration test for {@link DLFileSystem}. - */ -public abstract class TestDLFSBase extends TestDistributedLogBase { - - @Rule - public final TestName runtime = new TestName(); - - protected static URI dlfsUri; - protected static DLFileSystem fs; - - @BeforeClass - public static void setupDLFS() throws Exception { - setupCluster(); - dlfsUri = DLMTestUtil.createDLMURI(zkPort, ""); - fs = new DLFileSystem(); - Configuration conf = new Configuration(); - conf.set(DLFileSystem.DLFS_CONF_FILE, TestDLFSBase.class.getResource("/dlfs.conf").toURI().getPath()); - fs.initialize(dlfsUri, conf); - fs.setWorkingDirectory(new Path("/")); - } - - @AfterClass - public static void teardownDLFS() throws Exception { - fs.close(); - teardownCluster(); - } - -} diff --git a/stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFileSystem.java b/stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFileSystem.java deleted file mode 100644 index 4a2fc9e321d..00000000000 --- a/stream/distributedlog/io/dlfs/src/test/java/org/apache/distributedlog/fs/TestDLFileSystem.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.distributedlog.fs; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.InputStreamReader; -import lombok.extern.slf4j.Slf4j; -import org.apache.hadoop.fs.FSDataInputStream; -import org.apache.hadoop.fs.FSDataOutputStream; -import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.Path; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Integration test for {@link DLFileSystem}. - */ -@Slf4j -public class TestDLFileSystem extends TestDLFSBase { - - @Rule - public TemporaryFolder tmpDir = new TemporaryFolder(); - - @Test(expected = FileNotFoundException.class) - public void testOpenFileNotFound() throws Exception { - Path path = new Path("not-found-file"); - fs.open(path, 1024); - } - - @Test - public void testBasicIO() throws Exception { - Path path = new Path("/path/to/" + runtime.getMethodName()); - - assertFalse(fs.exists(path)); - - try (FSDataOutputStream out = fs.create(path)) { - for (int i = 0; i < 100; i++) { - out.writeBytes("line-" + i + "\n"); - } - out.flush(); - } - assertTrue(fs.exists(path)); - - File tempFile = tmpDir.newFile(); - Path localDst = new Path(tempFile.getPath()); - // copy the file - fs.copyToLocalFile(path, localDst); - // copy the file to dest - fs.copyFromLocalFile(localDst, new Path(runtime.getMethodName() + "-copied")); - - // rename - Path dstPath = new Path(runtime.getMethodName() + "-renamed"); - fs.rename(path, dstPath); - assertFalse(fs.exists(path)); - assertTrue(fs.exists(dstPath)); - - try (BufferedReader reader = new BufferedReader(new InputStreamReader(fs.open(dstPath, 1134)))) { - int lineno = 0; - String line; - while ((line = reader.readLine()) != null) { - assertEquals("line-" + lineno, line); - ++lineno; - } - assertEquals(100, lineno); - } - - - // delete the file - fs.delete(dstPath, false); - assertFalse(fs.exists(dstPath)); - } - - @Test - public void testListStatuses() throws Exception { - Path parentPath = new Path("/path/to/" + runtime.getMethodName()); - assertFalse(fs.exists(parentPath)); - try (FSDataOutputStream parentOut = fs.create(parentPath)) { - parentOut.writeBytes("parent"); - parentOut.flush(); - } - assertTrue(fs.exists(parentPath)); - - int numLogs = 3; - for (int i = 0; i < numLogs; i++) { - Path path = new Path("/path/to/" + runtime.getMethodName() - + "/" + runtime.getMethodName() + "-" + i); - assertFalse(fs.exists(path)); - try (FSDataOutputStream out = fs.create(path)) { - out.writeBytes("line"); - out.flush(); - } - assertTrue(fs.exists(path)); - } - FileStatus[] files = fs.listStatus(new Path("/path/to/" + runtime.getMethodName())); - - assertEquals(3, files.length); - for (int i = 0; i < numLogs; i++) { - FileStatus file = files[i]; - assertEquals(4, file.getLen()); - assertFalse(file.isDirectory()); - assertEquals(3, file.getReplication()); - assertEquals(0L, file.getModificationTime()); - assertEquals( - new Path("/path/to/" + runtime.getMethodName() + "/" + runtime.getMethodName() + "-" + i), - file.getPath()); - } - } - - @Test - public void testMkDirs() throws Exception { - Path path = new Path("/path/to/" + runtime.getMethodName()); - assertFalse(fs.exists(path)); - assertTrue(fs.mkdirs(path)); - assertTrue(fs.exists(path)); - assertTrue(fs.mkdirs(path)); - } - - @Test(expected = UnsupportedOperationException.class) - public void testTruncation() throws Exception { - Path path = new Path("/path/to/" + runtime.getMethodName()); - fs.truncate(path, 10); - } - - @Test - public void testDeleteRecursive() throws Exception { - int numLogs = 3; - for (int i = 0; i < numLogs; i++) { - Path path = new Path("/path/to/" + runtime.getMethodName() - + "/" + runtime.getMethodName() + "-" + i); - assertFalse(fs.exists(path)); - try (FSDataOutputStream out = fs.create(path)) { - out.writeBytes("line"); - out.flush(); - } - assertTrue(fs.exists(path)); - } - - fs.delete(new Path("/path/to/" + runtime.getMethodName()), true); - FileStatus[] files = fs.listStatus(new Path("/path/to/" + runtime.getMethodName())); - assertEquals(0, files.length); - } - - @Test - public void testCreateOverwrite() throws Exception { - Path path = new Path("/path/to/" + runtime.getMethodName()); - assertFalse(fs.exists(path)); - byte[] originData = "original".getBytes(UTF_8); - try (FSDataOutputStream out = fs.create(path)) { - out.write(originData); - out.flush(); - } - - try (FSDataInputStream in = fs.open(path, 1024)) { - assertEquals(originData.length, in.available()); - byte[] readData = new byte[originData.length]; - assertEquals(originData.length, in.read(readData)); - assertArrayEquals(originData, readData); - } - - byte[] overwrittenData = "overwritten".getBytes(UTF_8); - try (FSDataOutputStream out = fs.create(path, true)) { - out.write(overwrittenData); - out.flush(); - } - - try (FSDataInputStream in = fs.open(path, 1024)) { - assertEquals(overwrittenData.length, in.available()); - byte[] readData = new byte[overwrittenData.length]; - assertEquals(overwrittenData.length, in.read(readData)); - assertArrayEquals(overwrittenData, readData); - } - } - - @Test - public void testAppend() throws Exception { - Path path = new Path("/path/to/" + runtime.getMethodName()); - assertFalse(fs.exists(path)); - byte[] originData = "original".getBytes(UTF_8); - try (FSDataOutputStream out = fs.create(path)) { - out.write(originData); - out.flush(); - } - - try (FSDataInputStream in = fs.open(path, 1024)) { - assertEquals(originData.length, in.available()); - byte[] readData = new byte[originData.length]; - assertEquals(originData.length, in.read(readData)); - assertArrayEquals(originData, readData); - } - - byte[] appendData = "append".getBytes(UTF_8); - try (FSDataOutputStream out = fs.append(path, 1024)) { - out.write(appendData); - out.flush(); - } - - try (FSDataInputStream in = fs.open(path, 1024)) { - assertEquals(originData.length + appendData.length, in.available()); - byte[] readData = new byte[originData.length]; - assertEquals(originData.length, in.read(readData)); - assertArrayEquals(originData, readData); - readData = new byte[appendData.length]; - assertEquals(appendData.length, in.read(readData)); - assertArrayEquals(appendData, readData); - } - } - -} diff --git a/stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestDLSN.java b/stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestDLSN.java deleted file mode 100644 index fc3c58a0419..00000000000 --- a/stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestDLSN.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import org.junit.Test; - -/** - * Test Case for {@link DLSN}. - */ -public class TestDLSN { - - @Test(timeout = 60000) - public void testDLSN() { - DLSN dlsn = new DLSN(99L, 88L, 77L); - String dlsnv0 = dlsn.serialize(DLSN.VERSION0); - String dlsnv1 = dlsn.serialize(DLSN.VERSION1); - String badDLSN = "baddlsn"; - - assertEquals(dlsn, DLSN.deserialize(dlsnv0)); - assertEquals(dlsn, DLSN.deserialize(dlsnv1)); - try { - DLSN.deserialize(badDLSN); - fail("Should fail on deserializing bad dlsn"); - } catch (IllegalArgumentException iae) { - } - - assertEquals(dlsn, DLSN.deserialize0(dlsnv0)); - try { - DLSN.deserialize0(dlsnv1); - fail("Should fail on deserializing version one dlsn"); - } catch (IllegalArgumentException iae) { - } - try { - DLSN.deserialize0(badDLSN); - fail("Should fail on deserializing bad dlsn"); - } catch (IllegalArgumentException iae) { - } - } - - @Test(timeout = 60000) - public void testSerializeDeserializeBytes() { - DLSN dlsn = new DLSN(99L, 88L, 77L); - byte[] data = dlsn.serializeBytes(); - assertEquals(dlsn, DLSN.deserializeBytes(data)); - } -} diff --git a/stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestLogRecordSet.java b/stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestLogRecordSet.java deleted file mode 100644 index a85920e68af..00000000000 --- a/stream/distributedlog/protocol/src/test/java/org/apache/distributedlog/TestLogRecordSet.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.distributedlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.distributedlog.LogRecord.MAX_LOGRECORD_SIZE; -import static org.apache.distributedlog.LogRecordSet.HEADER_LEN; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import java.nio.ByteBuffer; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.distributedlog.LogRecordSet.Reader; -import org.apache.distributedlog.LogRecordSet.Writer; -import org.apache.distributedlog.exceptions.LogRecordTooLongException; -import org.apache.distributedlog.io.CompressionCodec.Type; -import org.junit.Test; - -/** - * Test Case for {@link LogRecordSet}. - */ -@Slf4j -public class TestLogRecordSet { - - @Test(timeout = 60000) - public void testEmptyRecordSet() throws Exception { - Writer writer = LogRecordSet.newWriter(1024, Type.NONE); - assertEquals("zero user bytes", HEADER_LEN, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - ByteBuf buffer = writer.getBuffer(); - assertEquals("zero user bytes", HEADER_LEN, buffer.readableBytes()); - - LogRecordWithDLSN record = new LogRecordWithDLSN( - new DLSN(1L, 0L, 0L), - 1L, - buffer, - 1L); - record.setRecordSet(); - Reader reader = LogRecordSet.of(record); - assertNull("Empty record set should return null", - reader.nextRecord()); - reader.release(); - } - - @Test(timeout = 60000) - public void testWriteTooLongRecord() throws Exception { - Writer writer = LogRecordSet.newWriter(1024, Type.NONE); - assertEquals("zero user bytes", HEADER_LEN, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - ByteBuffer dataBuf = ByteBuffer.allocate(MAX_LOGRECORD_SIZE + 1); - try { - writer.writeRecord(dataBuf, new CompletableFuture()); - fail("Should fail on writing large record"); - } catch (LogRecordTooLongException lrtle) { - // expected - } - assertEquals("zero user bytes", HEADER_LEN, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - ByteBuf buffer = writer.getBuffer(); - assertEquals("zero user bytes", HEADER_LEN, buffer.readableBytes()); - - LogRecordWithDLSN record = new LogRecordWithDLSN( - new DLSN(1L, 0L, 0L), - 1L, - buffer, - 1L); - record.setRecordSet(); - Reader reader = LogRecordSet.of(record); - assertNull("Empty record set should return null", - reader.nextRecord()); - reader.release(); - } - - @Test(timeout = 20000) - public void testWriteRecordsNoneCompressed() throws Exception { - testWriteRecords(Type.NONE); - } - - @Test(timeout = 20000) - public void testWriteRecordsLZ4Compressed() throws Exception { - testWriteRecords(Type.LZ4); - } - - void testWriteRecords(Type codec) throws Exception { - Writer writer = LogRecordSet.newWriter(1024, codec); - assertEquals("zero user bytes", HEADER_LEN, writer.getNumBytes()); - assertEquals("zero records", 0, writer.getNumRecords()); - - List> writePromiseList = Lists.newArrayList(); - /// write first 5 records - for (int i = 0; i < 5; i++) { - ByteBuffer record = ByteBuffer.wrap(("record-" + i).getBytes(UTF_8)); - CompletableFuture writePromise = new CompletableFuture<>(); - writer.writeRecord(record, writePromise); - writePromiseList.add(writePromise); - assertEquals((i + 1) + " records", (i + 1), writer.getNumRecords()); - } - ByteBuffer dataBuf = ByteBuffer.allocate(MAX_LOGRECORD_SIZE + 1); - try { - writer.writeRecord(dataBuf, new CompletableFuture<>()); - fail("Should fail on writing large record"); - } catch (LogRecordTooLongException lrtle) { - // expected - } - assertEquals("5 records", 5, writer.getNumRecords()); - - /// write another 5 records - for (int i = 0; i < 5; i++) { - ByteBuffer record = ByteBuffer.wrap(("record-" + (i + 5)).getBytes(UTF_8)); - CompletableFuture writePromise = new CompletableFuture<>(); - writer.writeRecord(record, writePromise); - writePromiseList.add(writePromise); - assertEquals((i + 6) + " records", (i + 6), writer.getNumRecords()); - } - - ByteBuf buffer = writer.getBuffer(); - assertEquals("10 records", 10, writer.getNumRecords()); - - // Test transmit complete - writer.completeTransmit(1L, 1L, 10L); - List writeResults = FutureUtils.result(FutureUtils.collect(writePromiseList)); - for (int i = 0; i < 10; i++) { - assertEquals(new DLSN(1L, 1L, 10L + i), writeResults.get(i)); - } - - LogRecordWithDLSN record = new LogRecordWithDLSN( - new DLSN(1L, 1L, 10L), - 99L, - buffer, - 999L); - record.setPositionWithinLogSegment(888); - record.setRecordSet(); - Reader reader = LogRecordSet.of(record); - LogRecordWithDLSN readRecord = reader.nextRecord(); - int numReads = 0; - while (null != readRecord) { - assertEquals(new DLSN(1L, 1L, 10L + numReads), readRecord.getDlsn()); - assertEquals(99L, readRecord.getTransactionId()); - assertEquals(888 + numReads, readRecord.getPositionWithinLogSegment()); - assertEquals(999L, readRecord.getStartSequenceIdOfCurrentSegment()); - assertEquals(999L + 888 + numReads - 1, readRecord.getSequenceId()); - // read next - ++numReads; - readRecord = reader.nextRecord(); - } - assertEquals(10, numReads); - reader.release(); - } - -} diff --git a/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/TestStreamRange.java b/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/TestStreamRange.java deleted file mode 100644 index 41daf8c481d..00000000000 --- a/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/TestStreamRange.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.protocol; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for {@link RangeId}. - */ -public class TestStreamRange { - - @Test - public void testConstructor() { - RangeId sr = RangeId.of(1234L, 5678L); - assertEquals(1234L, sr.getStreamId()); - assertEquals(5678L, sr.getRangeId()); - } - - @Test - public void testEqual() { - RangeId sr1 = RangeId.of(1234L, 5678L); - RangeId sr2 = RangeId.of(1234L, 5678L); - RangeId sr3 = RangeId.of(1234L, 5679L); - RangeId sr4 = RangeId.of(1235L, 5679L); - - assertTrue(sr1.equals(sr2)); - assertFalse(sr1.equals(sr3)); - assertFalse(sr1.equals(sr4)); - assertFalse(sr3.equals(sr4)); - } - - @Test - public void testToString() { - RangeId sr = RangeId.of(1234L, 5678L); - assertEquals("range(1234, 5678)", sr.toString()); - } - -} diff --git a/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java b/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java deleted file mode 100644 index 9d1b7289246..00000000000 --- a/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.protocol.util; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.isStreamCreated; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.isStreamWritable; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.keyRangeOverlaps; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.validateNamespaceName; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.validateStreamName; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.RangeProperties; -import org.apache.bookkeeper.stream.proto.StreamMetadata.LifecycleState; -import org.apache.bookkeeper.stream.proto.StreamMetadata.ServingState; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test of {@link ProtoUtils}. - */ -public class TestProtoUtils { - - @Rule - public final TestName name = new TestName(); - - @Test - public void testValidateNamespaceName() { - assertTrue(validateNamespaceName("namespace_name")); - assertTrue(validateNamespaceName("NamespaceName")); - assertTrue(validateNamespaceName("9NamespaceName")); - assertTrue(validateNamespaceName("namespace-name")); - assertTrue(validateNamespaceName("!namespace_name")); - assertFalse(validateNamespaceName(" namespace_name")); - assertFalse(validateNamespaceName("namespace_name")); - assertFalse(validateNamespaceName("")); - assertFalse(validateNamespaceName(null)); - } - - @Test - public void testValidateStreamName() { - assertTrue(validateStreamName("stream_name")); - assertTrue(validateStreamName("StreamName")); - assertTrue(validateStreamName("9StreamName")); - assertTrue(validateStreamName("stream-name")); - assertTrue(validateStreamName("!stream_name")); - assertFalse(validateNamespaceName(" stream_name")); - assertFalse(validateNamespaceName("stream_name")); - assertFalse(validateNamespaceName("")); - assertFalse(validateNamespaceName(null)); - } - - @Test - public void testKeyRangeOverlaps1() { - assertFalse(keyRangeOverlaps(1000L, 2000L, 3000L, 4000L)); - assertTrue(keyRangeOverlaps(1000L, 2000L, 1500L, 2500L)); - assertTrue(keyRangeOverlaps(1000L, 2000L, 1500L, 1800L)); - assertTrue(keyRangeOverlaps(1000L, 3500L, 3000L, 4000L)); - assertTrue(keyRangeOverlaps(3200L, 3500L, 3000L, 4000L)); - } - - @Test - public void testKeyRangeOverlaps2() { - assertFalse(keyRangeOverlaps( - Pair.of(1000L, 2000L), - Pair.of(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - Pair.of(1000L, 2000L), - Pair.of(1500L, 2500L))); - assertTrue(keyRangeOverlaps( - Pair.of(1000L, 2000L), - Pair.of(1500L, 1800L))); - assertTrue(keyRangeOverlaps( - Pair.of(1000L, 3500L), - Pair.of(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - Pair.of(3200L, 3500L), - Pair.of(3000L, 4000L))); - } - - private static RangeProperties createRangeMeta(long startKey, long endKey) { - return RangeProperties.newBuilder() - .setStartHashKey(startKey) - .setEndHashKey(endKey) - .setStorageContainerId(1234L) - .setRangeId(1234L) - .build(); - } - - @Test - public void testKeyRangeOverlaps3() { - assertFalse(keyRangeOverlaps( - createRangeMeta(1000L, 2000L), - createRangeMeta(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(1000L, 2000L), - createRangeMeta(1500L, 2500L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(1000L, 2000L), - createRangeMeta(1500L, 1800L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(1000L, 3500L), - createRangeMeta(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(3200L, 3500L), - createRangeMeta(3000L, 4000L))); - } - - @Test - public void testKeyRangeOverlaps4() { - assertFalse(keyRangeOverlaps( - createRangeMeta(1000L, 2000L), - Pair.of(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(1000L, 2000L), - Pair.of(1500L, 2500L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(1000L, 2000L), - Pair.of(1500L, 1800L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(1000L, 3500L), - Pair.of(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - createRangeMeta(3200L, 3500L), - Pair.of(3000L, 4000L))); - } - - @Test - public void testKeyRangeOverlaps5() { - assertFalse(keyRangeOverlaps( - Pair.of(1000L, 2000L), - createRangeMeta(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - Pair.of(1000L, 2000L), - createRangeMeta(1500L, 2500L))); - assertTrue(keyRangeOverlaps( - Pair.of(1000L, 2000L), - createRangeMeta(1500L, 1800L))); - assertTrue(keyRangeOverlaps( - Pair.of(1000L, 3500L), - createRangeMeta(3000L, 4000L))); - assertTrue(keyRangeOverlaps( - Pair.of(3200L, 3500L), - createRangeMeta(3000L, 4000L))); - } - - @Test - public void testIsStreamCreated() { - assertFalse(isStreamCreated(LifecycleState.UNINIT)); - assertFalse(isStreamCreated(LifecycleState.CREATING)); - assertTrue(isStreamCreated(LifecycleState.CREATED)); - assertTrue(isStreamCreated(LifecycleState.FENCING)); - assertTrue(isStreamCreated(LifecycleState.FENCED)); - } - - @Test - public void testIsStreamWritable() { - assertTrue(isStreamWritable(ServingState.WRITABLE)); - assertFalse(isStreamWritable(ServingState.READONLY)); - } - - // - // Namespace API - // - - @Test - public void testCreateCreateNamespaceRequest() { - NamespaceConfiguration nsConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - CreateNamespaceRequest request = createCreateNamespaceRequest( - name.getMethodName(), - nsConf); - assertEquals(name.getMethodName(), request.getName()); - assertEquals(nsConf, request.getNsConf()); - } - - @Test - public void testCreateDeleteNamespaceRequest() { - DeleteNamespaceRequest request = createDeleteNamespaceRequest( - name.getMethodName()); - assertEquals(name.getMethodName(), request.getName()); - } - - @Test - public void testCreateGetNamespaceRequest() { - GetNamespaceRequest request = createGetNamespaceRequest( - name.getMethodName()); - assertEquals(name.getMethodName(), request.getName()); - } - -} diff --git a/stream/server/src/test/java/org/apache/bookkeeper/stream/server/TestStorageServerMain.java b/stream/server/src/test/java/org/apache/bookkeeper/stream/server/TestStorageServerMain.java deleted file mode 100644 index cec6c525c89..00000000000 --- a/stream/server/src/test/java/org/apache/bookkeeper/stream/server/TestStorageServerMain.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.stream.server; - -import static org.junit.Assert.assertEquals; - -import com.beust.jcommander.ParameterException; -import org.junit.Test; - -/** - * Unit test of {@link StorageServer#main(String[])}. - */ -public class TestStorageServerMain { - - @Test - public void testHelp() { - assertEquals( - ExitCode.INVALID_CONF.code(), - StorageServer.doMain(new String[]{"-h"})); - } - - @Test(expected = ParameterException.class) - public void testIllegalPort() { - assertEquals( - ExitCode.INVALID_CONF.code(), - StorageServer.doMain(new String[]{"-p", "abcd"})); - } - -} diff --git a/stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java b/stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java deleted file mode 100644 index 4cfbea1d592..00000000000 --- a/stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.stream.server.grpc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import io.grpc.util.MutableHandlerRegistry; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stream.server.StorageServer; -import org.apache.bookkeeper.stream.server.conf.StorageServerConfiguration; -import org.apache.bookkeeper.stream.storage.impl.StorageContainerStoreImpl; -import org.apache.commons.configuration.CompositeConfiguration; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test of {@link GrpcServer}. - */ -public class TestGrpcServer { - - @Rule - public TestName name = new TestName(); - - private final CompositeConfiguration compConf = new CompositeConfiguration(); - - @Test - public void testCreateLocalServer() { - GrpcServer server = new GrpcServer( - mock(StorageContainerStoreImpl.class), - StorageServerConfiguration.of(compConf), - null, - name.getMethodName(), - new MutableHandlerRegistry(), - NullStatsLogger.INSTANCE); - server.start(); - assertEquals(-1, server.getGrpcServer().getPort()); - server.close(); - } - - @Test - public void testCreateBindServer() throws Exception { - GrpcServer server = new GrpcServer( - mock(StorageContainerStoreImpl.class), - StorageServerConfiguration.of(compConf), - StorageServer.createLocalEndpoint(0, false), - null, - null, - NullStatsLogger.INSTANCE); - server.start(); - assertTrue(server.getGrpcServer().getPort() > 0); - server.close(); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestKVUtils.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestKVUtils.java deleted file mode 100644 index e22dbb501da..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestKVUtils.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.impl.kv; - -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.ByteBuf; -import lombok.Cleanup; -import org.apache.bookkeeper.proto.statestore.kv.Command; -import org.junit.Test; - -/** - * Unit test for {@link KVUtils}. - */ -public class TestKVUtils { - - @Test - public void testNewLogRecordBuf() throws Exception { - Command command = KVUtils.NOP_CMD; - @Cleanup("release") ByteBuf buffer = KVUtils.newCommandBuf(command); - assertEquals(command.getSerializedSize(), buffer.readableBytes()); - Command another = KVUtils.newCommand(buffer); - assertEquals(command, another); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStore.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStore.java deleted file mode 100644 index 8b29b1ceb97..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStore.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.impl.kv; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertNull; - -import java.io.File; -import java.net.URI; -import java.nio.file.Files; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.coder.ByteArrayCoder; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.commons.io.FileUtils; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * Unit test of {@link RocksdbKVStore}. - */ -@Slf4j -public class TestRocksdbKVAsyncStore extends TestDistributedLogBase { - - private static URI uri; - private static Namespace namespace; - - @BeforeClass - public static void setupCluster() throws Exception { - TestDistributedLogBase.setupCluster(); - uri = DLMTestUtil.createDLMURI(zkPort, "/mvcc"); - conf.setPeriodicFlushFrequencyMilliSeconds(2); - conf.setWriteLockEnabled(false); - namespace = NamespaceBuilder.newBuilder() - .conf(conf) - .uri(uri) - .clientId("test-mvcc-async-store") - .build(); - } - - @AfterClass - public static void teardownCluster() throws Exception { - if (null != namespace) { - namespace.close(); - } - TestDistributedLogBase.teardownCluster(); - } - - private String streamName; - private File tempDir; - private RocksdbKVAsyncStore store; - - @Before - @Override - public void setup() throws Exception { - super.setup(); - ensureURICreated(uri); - - tempDir = Files.createTempDirectory("test").toFile(); - - store = new RocksdbKVAsyncStore<>( - () -> new RocksdbKVStore<>(), - () -> namespace); - } - - private StateStoreSpec initSpec(String streamName) { - return StateStoreSpec.builder() - .name(streamName) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .stream(streamName) - .localStateStoreDir(tempDir) - .build(); - } - - @After - @Override - public void teardown() throws Exception { - if (null != streamName) { - namespace.deleteLog(streamName); - } - - if (null != store) { - store.close(); - } - if (null != tempDir) { - FileUtils.deleteDirectory(tempDir); - } - super.teardown(); - } - - @Test(expected = NullPointerException.class) - public void testInitMissingStreamName() throws Exception { - this.streamName = "test-init-missing-stream-name"; - StateStoreSpec spec = StateStoreSpec.builder() - .name(streamName) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .localStateStoreDir(tempDir) - .build(); - result(store.init(spec)); - } - - private byte[] getKey(int i) { - return String.format("key-%05d", i).getBytes(UTF_8); - } - - private byte[] getValue(int i) { - return String.format("value-%05d", i).getBytes(UTF_8); - } - - @Test - public void testBasicOps() throws Exception { - this.streamName = "test-basic-ops"; - StateStoreSpec spec = initSpec(streamName); - result(store.init(spec)); - - // normal put - { - assertNull(result(store.get(getKey(0)))); - result(store.put(getKey(0), getValue(0))); - assertArrayEquals(getValue(0), result(store.get(getKey(0)))); - } - - // putIfAbsent - { - // failure case - assertArrayEquals(getValue(0), result(store.putIfAbsent(getKey(0), getValue(99)))); - assertArrayEquals(getValue(0), result(store.get(getKey(0)))); - // success case - byte[] key1 = getKey(1); - assertNull(result(store.putIfAbsent(key1, getValue(1)))); - assertArrayEquals(getValue(1), result(store.get(key1))); - } - - // delete(k) - { - // key not found - assertNull(result(store.delete(getKey(99)))); - // key exists - int key = 0; - assertArrayEquals(getValue(key), result(store.get(getKey(key)))); - assertArrayEquals(getValue(key), result(store.delete(getKey(key)))); - assertNull(result(store.get(getKey(key)))); - } - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStoreWithCheckpoints.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStoreWithCheckpoints.java deleted file mode 100644 index 904e8531243..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVAsyncStoreWithCheckpoints.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.impl.kv; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.apache.bookkeeper.statelib.testing.executors.MockExecutorController.THREAD_NAME_PREFIX; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.io.File; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.time.Duration; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.coder.ByteArrayCoder; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.bookkeeper.statelib.api.exceptions.InvalidStateStoreException; -import org.apache.bookkeeper.statelib.impl.rocksdb.RocksUtils; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.fs.FSCheckpointManager; -import org.apache.bookkeeper.statelib.testing.executors.MockExecutorController; -import org.apache.commons.io.FileUtils; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; - -/** - * Unit test of {@link RocksdbKVStore}. - */ -@Slf4j -public class TestRocksdbKVAsyncStoreWithCheckpoints extends TestDistributedLogBase { - - private static URI uri; - private static Namespace namespace; - - @BeforeClass - public static void setupCluster() throws Exception { - TestDistributedLogBase.setupCluster(); - uri = DLMTestUtil.createDLMURI(zkPort, "/mvcc"); - conf.setPeriodicFlushFrequencyMilliSeconds(2); - conf.setWriteLockEnabled(false); - conf.setExplicitTruncationByApplication(true); - namespace = NamespaceBuilder.newBuilder() - .conf(conf) - .uri(uri) - .clientId("test-mvcc-async-store") - .build(); - } - - @AfterClass - public static void teardownCluster() throws Exception { - if (null != namespace) { - namespace.close(); - } - TestDistributedLogBase.teardownCluster(); - } - - @Rule - public final TestName runtime = new TestName(); - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - - private String streamName; - private RocksdbKVAsyncStore store; - private ScheduledExecutorService mockWriteExecutor; - private ExecutorService realWriteExecutor; - private MockExecutorController writeExecutorController; - private ScheduledExecutorService checkpointExecutor; - private FSCheckpointManager checkpointStore; - private File localDir; - private File remoteDir; - - @Before - @Override - public void setup() throws Exception { - super.setup(); - ensureURICreated(uri); - - localDir = testDir.newFolder("local"); - remoteDir = testDir.newFolder("remote"); - - checkpointStore = new FSCheckpointManager(remoteDir); - - // initialize the scheduler - realWriteExecutor = Executors.newSingleThreadExecutor( - new ThreadFactoryBuilder().setNameFormat(THREAD_NAME_PREFIX + "%d").build()); - mockWriteExecutor = mock(ScheduledExecutorService.class); - writeExecutorController = new MockExecutorController(realWriteExecutor) - .controlExecute(mockWriteExecutor) - .controlSubmit(mockWriteExecutor) - .controlSchedule(mockWriteExecutor) - .controlScheduleAtFixedRate(mockWriteExecutor, 5); - - checkpointExecutor = Executors.newSingleThreadScheduledExecutor(); - - store = new RocksdbKVAsyncStore<>( - () -> new RocksdbKVStore<>(), - () -> namespace); - FutureUtils.result(store.init(initSpec(runtime.getMethodName()))); - } - - private StateStoreSpec initSpec(String streamName) { - return StateStoreSpec.builder() - .name(streamName) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .stream(streamName) - .localStateStoreDir(localDir) - .writeIOScheduler(mockWriteExecutor) - .checkpointStore(checkpointStore) - .checkpointIOScheduler(checkpointExecutor) - .checkpointDuration(Duration.ofMinutes(1)) - .checkpointChecksumEnable(true) - .checkpointChecksumCompatible(false) - .build(); - } - - @After - @Override - public void teardown() throws Exception { - if (null != streamName) { - namespace.deleteLog(streamName); - } - - if (null != store) { - store.close(); - } - - if (null != checkpointExecutor) { - checkpointExecutor.shutdown(); - } - - if (null != realWriteExecutor) { - realWriteExecutor.shutdown(); - } - - if (null != checkpointStore) { - checkpointStore.close(); - } - - super.teardown(); - } - - @Test(expected = NullPointerException.class) - public void testInitMissingStreamName() throws Exception { - this.streamName = "test-init-missing-stream-name"; - StateStoreSpec spec = StateStoreSpec.builder() - .name(streamName) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .localStateStoreDir(localDir) - .build(); - result(store.init(spec)); - } - - private byte[] getKey(int i) { - return String.format("key-%05d", i).getBytes(UTF_8); - } - - private byte[] getValue(int i) { - return String.format("value-%05d", i).getBytes(UTF_8); - } - - private void writeNumKvs(int numKvs, int startIdx) throws Exception { - CompletableFuture lastWrite = null; - for (int i = 0; i < numKvs; i++) { - byte[] key = getKey(startIdx + i); - byte[] val = getValue(startIdx + i); - - lastWrite = store.put(key, val); - } - FutureUtils.result(lastWrite); - } - - private void readNumKvs(int numKvs, int startIdx) throws Exception { - for (int i = 0; i < numKvs; i++) { - byte[] key = getKey(startIdx + i); - - byte[] expectedVal = getValue(startIdx + i); - byte[] actualVal = FutureUtils.result(store.get(key)); - - assertArrayEquals(expectedVal, actualVal); - } - } - - - @Test - public void testRestartNoCheckpoint() throws Exception { - final int numKvs = 100; - - // write 100 kvs - writeNumKvs(numKvs, 0); - - // close the store - store.close(); - - // since the lock isn't advanced so no checkpoint is created. - List files = checkpointStore.listFiles(RocksUtils.getDestCheckpointsPath(store.name())); - assertTrue(files.isEmpty()); - - // remove local dir - FileUtils.deleteDirectory(new File(localDir.getAbsolutePath())); - - // reload the store - store = new RocksdbKVAsyncStore<>( - () -> new RocksdbKVStore<>(), - () -> namespace); - FutureUtils.result(store.init(initSpec(runtime.getMethodName()))); - - assertTrue(Files.exists( - Paths.get(localDir.getAbsolutePath()))); - - // verify the 100 kvs - readNumKvs(numKvs, 0); - } - - @Test - public void testRestartWithCheckpoint() throws Exception { - final int numKvs = 100; - - // write 100 kvs - writeNumKvs(numKvs, 0); - - // advance the clock to trigger checkpointing - writeExecutorController.advance(Duration.ofMinutes(1)); - - // ensure checkpoint completed - checkpointExecutor.submit(() -> { - }).get(); - - store.close(); - - List files = checkpointStore.listFiles(RocksUtils.getDestCheckpointsPath(store.name())); - assertEquals(1, files.size()); - - // remove local dir - FileUtils.deleteDirectory(new File(localDir.getAbsolutePath())); - - // reload the store - store = new RocksdbKVAsyncStore<>( - () -> new RocksdbKVStore<>(), - () -> namespace); - FutureUtils.result(store.init(initSpec(runtime.getMethodName()))); - - assertTrue(Files.exists( - Paths.get(localDir.getAbsolutePath()))); - - // verify the 100 kvs - readNumKvs(numKvs, 0); - } - - private void reinitStore(StateStoreSpec spec) throws Exception { - store.close(); - - // remove local dir - FileUtils.deleteDirectory(new File(localDir.getAbsolutePath())); - - store = new RocksdbKVAsyncStore<>( - () -> new RocksdbKVStore<>(), - () -> namespace); - result(store.init(spec)); - } - - @Test - public void testMissingData() throws Exception { - int numKeys = 100; - this.streamName = runtime.getMethodName(); - StateStoreSpec spec = initSpec(runtime.getMethodName()); - - reinitStore(spec); - - writeNumKvs(numKeys, 0); - readNumKvs(numKeys, 0); - - // Reload store from Journal - reinitStore(spec); - - readNumKvs(numKeys, 0); - - // Trigger a checkpoint - store.getLocalStore().checkpoint(); - // ensure checkpoint completed - checkpointExecutor.submit(() -> {}).get(); - - writeNumKvs(numKeys, 100); - - reinitStore(spec); - - // Validate that we can load from both checkpoint and journal - readNumKvs(numKeys, 0); - readNumKvs(numKeys, 100); - - // Add some more data - writeNumKvs(numKeys, 200); - DLSN dlsn = store.getLastDLSN(); - - // Truncate and purge part of Journal - result(store.truncateJournal(dlsn)); - store.purgeOlderThan(Integer.MAX_VALUE); - - // reloading the statestore should fail. - try { - reinitStore(spec); - fail("Store initialization should fail due to missing data"); - } catch (InvalidStateStoreException isse) { - assertEquals( - "replayJournal failed: Invalid starting transaction 204 expecting 102 for stream testMissingData", - isse.getMessage()); - } - } -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStore.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStore.java deleted file mode 100644 index e4df408e4cf..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStore.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.statelib.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import java.io.File; -import org.apache.bookkeeper.common.coder.StringUtf8Coder; -import org.apache.bookkeeper.common.kv.KV; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.bookkeeper.statelib.api.exceptions.InvalidStateStoreException; -import org.apache.bookkeeper.statelib.api.exceptions.StateStoreRuntimeException; -import org.apache.bookkeeper.statelib.api.kv.KVIterator; -import org.apache.bookkeeper.statelib.api.kv.KVMulti; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test of {@link RocksdbKVStore}. - */ -public class TestRocksdbKVStore { - - @Rule - public final TestName runtime = new TestName(); - - private File tempDir; - private StateStoreSpec spec; - private RocksdbKVStore store; - - @Before - public void setUp() throws Exception { - tempDir = java.nio.file.Files.createTempDirectory("test").toFile(); - spec = StateStoreSpec.builder() - .name(runtime.getMethodName()) - .keyCoder(StringUtf8Coder.of()) - .valCoder(StringUtf8Coder.of()) - .localStateStoreDir(tempDir) - .stream(runtime.getMethodName()) - .build(); - store = new RocksdbKVStore<>(); - } - - @After - public void tearDown() throws Exception { - if (null != store) { - store.close(); - } - if (null != tempDir) { - FileUtils.deleteDirectory(tempDir); - } - } - - // - // Invalid Arguments Test Cases - // - - @Test(expected = NullPointerException.class) - public void testNullPut() throws Exception { - store.init(spec); - store.put(null, "val"); - } - - @Test(expected = NullPointerException.class) - public void testNullPutIfAbsent() throws Exception { - store.init(spec); - store.putIfAbsent(null, "val"); - } - - @Test(expected = NullPointerException.class) - public void testNullGet() throws Exception { - store.init(spec); - store.get(null); - } - - @Test(expected = NullPointerException.class) - public void testNullDelete() throws Exception { - store.init(spec); - store.delete(null); - } - - @Test(expected = NullPointerException.class) - public void testMultiNullPut() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.put(null, "val"); - } - - @Test(expected = NullPointerException.class) - public void testMultiNullDelete() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.delete(null); - } - - @Test(expected = NullPointerException.class) - public void testMultiNullDeleteRangeFrom() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.deleteRange(null, "to"); - } - - @Test(expected = NullPointerException.class) - public void testMultiNullDeleteRangeTo() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.deleteRange("from", null); - } - - @Test(expected = NullPointerException.class) - public void testMultiNullDeleteRangeBoth() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.deleteRange(null, null); - } - - // - // Invalid State Test Cases - // - - @Test(expected = InvalidStateStoreException.class) - public void testPutBeforeInit() throws Exception { - store.put("key", "val"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testPutIfAbsentBeforeInit() throws Exception { - store.putIfAbsent("key", "val"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testGetBeforeInit() throws Exception { - store.get("key"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testDeleteBeforeInit() throws Exception { - store.delete("key"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testRangeBeforeInit() throws Exception { - store.range("key1", "key2"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testMultiBeforeInit() throws Exception { - store.multi(); - } - - private void initThenClose() throws Exception { - store.init(spec); - store.close(); - } - - @Test(expected = InvalidStateStoreException.class) - public void testPutAfterClose() throws Exception { - initThenClose(); - store.put("key", "val"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testPutIfAbsentAfterClose() throws Exception { - initThenClose(); - store.putIfAbsent("key", "val"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testGetAfterClose() throws Exception { - initThenClose(); - store.get("key"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testDeleteAfterClose() throws Exception { - initThenClose(); - store.delete("key"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testRangeAfterClose() throws Exception { - initThenClose(); - store.range("key1", "key2"); - } - - @Test(expected = InvalidStateStoreException.class) - public void testMultiAfterClose() throws Exception { - initThenClose(); - store.multi(); - } - - @Test(expected = InvalidStateStoreException.class) - public void testMultiExecutionAfterClose() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.put("key", "value"); - multi.delete("key"); - store.close(); - multi.execute(); - } - - @Test - public void testPutAfterMultiExecuted() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.execute(); - try { - multi.put("key", "value"); - fail("Should fail put if a multi op is already executed"); - } catch (StateStoreRuntimeException sse) { - } - } - - @Test - public void testDeleteRangeAfterMultiExecuted() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.execute(); - try { - multi.deleteRange("from", "to"); - fail("Should fail put if a multi op is already executed"); - } catch (StateStoreRuntimeException sse) { - } - } - - @Test - public void testDeleteAfterMultiExecuted() throws Exception { - store.init(spec); - KVMulti multi = store.multi(); - multi.execute(); - try { - multi.delete("key"); - fail("Should fail put if a multi op is already executed"); - } catch (StateStoreRuntimeException sse) { - } - } - - // - // Operations - // - - @Test - public void testGetNull() throws Exception { - store.init(spec); - assertNull(store.get("key")); - } - - @Test - public void testGetValue() throws Exception { - store.init(spec); - store.put("key", "value"); - assertEquals("value", store.get("key")); - } - - private void writeKVs(int numPairs) { - KVMulti multi = store.multi(); - for (int i = 0; i < numPairs; i++) { - multi.put("key-" + i, "value-" + i); - } - multi.execute(); - } - - @Test - public void testAllRange() throws Exception { - store.init(spec); - writeKVs(10); - KVIterator iter = store.range(null, null); - int idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals("key-" + idx, kv.key()); - assertEquals("value-" + idx, kv.value()); - ++idx; - } - assertEquals(10, idx); - iter.close(); - } - - @Test - public void testHeadRange() throws Exception { - store.init(spec); - writeKVs(10); - KVIterator iter = store.range(null, "key-" + 5); - int idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals("key-" + idx, kv.key()); - assertEquals("value-" + idx, kv.value()); - ++idx; - } - assertEquals(6, idx); - iter.close(); - } - - @Test - public void testTailRange() throws Exception { - store.init(spec); - writeKVs(10); - KVIterator iter = store.range("key-" + 5, null); - int idx = 5; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals("key-" + idx, kv.key()); - assertEquals("value-" + idx, kv.value()); - ++idx; - } - assertEquals(10, idx); - iter.close(); - } - - @Test - public void testSubRange() throws Exception { - store.init(spec); - writeKVs(10); - KVIterator iter = store.range("key-" + 5, "key-" + 7); - int idx = 5; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals("key-" + idx, kv.key()); - assertEquals("value-" + idx, kv.value()); - ++idx; - } - assertEquals(8, idx); - iter.close(); - } - - @Test - public void testPutIfAbsent() throws Exception { - store.init(spec); - assertNull(store.putIfAbsent("key", "value")); - assertEquals("value", store.get("key")); - assertEquals("value", store.putIfAbsent("key", "another-value")); - assertEquals("value", store.putIfAbsent("key", null)); - } - - @Test - public void testDelete() throws Exception { - store.init(spec); - store.put("key", "value"); - assertEquals("value", store.get("key")); - assertEquals("value", store.delete("key")); - assertNull(store.get("key")); - } - - @Test - public void testPutNull() throws Exception { - store.init(spec); - store.put("key", "value"); - assertEquals("value", store.get("key")); - store.put("key", null); - assertNull(store.get("key")); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStoreCheckpoint.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStoreCheckpoint.java deleted file mode 100644 index d11ffa76ce6..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestRocksdbKVStoreCheckpoint.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.statelib.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.io.File; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.CheckpointInfo; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; - - - - -/** - * Test cases for Rocksdb KV Store with checkpoints. - */ -@Slf4j -public class TestRocksdbKVStoreCheckpoint { - - @Rule - public final TestName runtime = new TestName(); - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - - private TestStateStore store; - - @Before - public void setUp() throws Exception { - store = new TestStateStore(runtime, testDir); - store.enableCheckpoints(true); - store.init(); - } - - @After - public void tearDown() throws Exception { - if (null != store) { - store.close(); - } - } - - @Test - public void testRestoreCorruptCheckpoint() throws Exception { - int numKvs = 100; - - store.addNumKVs("transaction-1", numKvs, 0); - String checkpoint1 = store.checkpoint("checkpoint-1"); - assertEquals("transaction-1", store.get("transaction-id")); - - store.addNumKVs("transaction-2", numKvs, 100); - assertEquals("transaction-2", store.get("transaction-id")); - String checkpoint2 = store.checkpoint("checkpoint-2"); - - store.addNumKVs("transaction-3", numKvs, 200); - assertEquals("transaction-3", store.get("transaction-id")); - - store.destroyLocal(); - store.restore(); - assertEquals("transaction-2", store.get("transaction-id")); - - // Ensure we can write to new store - store.addNumKVs("transaction-4", numKvs, 300); - assertEquals("transaction-4", store.get("transaction-id")); - - // corrupt the checkpoint-2 so restore fails - - CheckpointInfo cpi = store.getLatestCheckpoint(); - store.corruptCheckpoint(cpi); - store.destroyLocal(); - - // latest checkpoint is checkpoint-2, which has been corrupted. - store.restore(); - // We should fallback to checkpoint-1 - assertEquals("transaction-1", store.get("transaction-id")); - } - - @Test - public void testLocalStoreCleanup() throws Exception { - File checkpointDir = new File(store.getLocalDir(), "checkpoints"); - - store.setRemoveLocal(true); - store.setRemoveRemote(true); - store.setLocalStorageCleanup(true); - - String[] checkpoints = checkpointDir.list(); - // Initially there is only one checkpoint directory that is used by the statestore - assertEquals(1, checkpoints.length); - - store.restore(); - - checkpoints = checkpointDir.list(); - // We should only have one checkpoint in the local directory. - assertEquals(1, checkpoints.length); - - int numKvs = 100; - for (int i = 0; i < 3; i++) { - String txid = "txid-" + i; - store.addNumKVs(txid, numKvs, i * numKvs); - String checkpoint1 = store.checkpoint("checkpoint-1"); - - checkpoints = checkpointDir.list(); - // Ensure the checkpoints are cleaned up - assertEquals(1, checkpoints.length); - - store.restore(); - assertEquals(txid, store.get("transaction-id")); - - checkpoints = checkpointDir.list(); - // We should only have one checkpoint in the local directory. - assertEquals(1, checkpoints.length); - } - - store.close(); - - checkpoints = checkpointDir.list(); - // We should not have any checkpoints af the store is closed. - assertNull(checkpoints); - } -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestStateStore.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestStateStore.java deleted file mode 100644 index c4a5b23002b..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/kv/TestStateStore.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - * - */ -package org.apache.bookkeeper.statelib.impl.kv; - -import com.google.common.io.MoreFiles; -import com.google.common.io.RecursiveDeleteOption; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeoutException; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.coder.StringUtf8Coder; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.bookkeeper.statelib.api.checkpoint.CheckpointStore; -import org.apache.bookkeeper.statelib.api.exceptions.StateStoreException; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.CheckpointInfo; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.RocksCheckpointer; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.RocksdbCheckpointTask; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.RocksdbRestoreTask; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.fs.FSCheckpointManager; -import org.apache.bookkeeper.stream.proto.kv.store.CheckpointMetadata; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; -import org.rocksdb.Checkpoint; - - -/** - * TestStateStore is a helper class for testing various statestore operations. - */ -@Slf4j -public class TestStateStore { - - private final String dbName; - private boolean removeLocal; - private boolean removeRemote; - - private File localDir; - private File localCheckpointsDir; - private File remoteDir; - private Path remoteCheckpointsPath; - private StateStoreSpec spec; - private RocksdbKVStore store; - private CheckpointStore checkpointStore; - private RocksdbCheckpointTask checkpointer; - private RocksdbRestoreTask restorer; - private ScheduledExecutorService checkpointExecutor; - private boolean checkpointChecksumEnable; - private boolean checkpointChecksumCompatible; - private boolean enableNonChecksumCompatibility; - private boolean localStorageCleanup; - private Duration checkpointRestoreIdleWait; - - public TestStateStore(String dbName, - File localDir, - File remoteDir, - boolean removeLocal, - boolean removeRemote) throws IOException { - this.dbName = dbName; - this.localDir = localDir; - this.remoteDir = remoteDir; - this.removeLocal = removeLocal; - this.removeRemote = removeRemote; - this.checkpointChecksumEnable = true; - this.checkpointChecksumCompatible = true; - this.localStorageCleanup = false; - localCheckpointsDir = new File(localDir, "checkpoints"); - remoteCheckpointsPath = Paths.get(remoteDir.getAbsolutePath(), dbName); - enableNonChecksumCompatibility = false; - } - public TestStateStore(TestName runtime, TemporaryFolder testDir) throws IOException { - this( - runtime.getMethodName(), - testDir.newFolder("local"), - testDir.newFolder("remote"), - false, - false - ); - } - - public void checkpointChecksumEnable(boolean val) { - checkpointChecksumEnable = val; - } - - public void checkpointChecksumCompatible(boolean val) { - checkpointChecksumCompatible = val; - } - - public File getLocalDir() { - return localDir; - } - - public File getRemoteDir() { - return remoteDir; - } - - public void enableCheckpoints(boolean enable) { - if (enable) { - checkpointExecutor = Executors.newSingleThreadScheduledExecutor(); - } else { - checkpointExecutor.shutdown(); - checkpointExecutor = null; - } - } - - public void setRemoveLocal(boolean enable) { - removeLocal = enable; - } - - public void setRemoveRemote(boolean enable) { - removeRemote = enable; - } - - public void setLocalStorageCleanup(boolean enable) { - localStorageCleanup = enable; - } - - public File getLocalCheckpointsDir() { - return localCheckpointsDir; - } - - public CheckpointStore getCheckpointStore() { - return checkpointStore; - } - - public void setCheckpointRestoreIdleWait(Duration d) { - checkpointRestoreIdleWait = d; - } - - public CheckpointStore newCheckpointStore() { - return new FSCheckpointManager(remoteDir); - } - - public void init() throws StateStoreException { - checkpointStore = newCheckpointStore(); - StateStoreSpec.StateStoreSpecBuilder builder = StateStoreSpec.builder() - .name(dbName) - .keyCoder(StringUtf8Coder.of()) - .valCoder(StringUtf8Coder.of()) - .localStateStoreDir(localDir) - .checkpointChecksumEnable(checkpointChecksumEnable) - .checkpointChecksumCompatible(checkpointChecksumCompatible) - .localStorageCleanupEnable(localStorageCleanup) - .stream(dbName); - if (checkpointExecutor != null) { - builder = builder.checkpointStore(checkpointStore) - .checkpointIOScheduler(checkpointExecutor); - } - if (checkpointRestoreIdleWait != null) { - builder = builder.checkpointRestoreIdleLimit(checkpointRestoreIdleWait); - } - spec = builder.build(); - store = new RocksdbKVStore<>(); - store.init(spec); - - this.checkpointer = new RocksdbCheckpointTask( - dbName, Checkpoint.create(store.getDb()), localCheckpointsDir, checkpointStore, - removeLocal, removeRemote, spec.isCheckpointChecksumEnable(), - spec.isCheckpointChecksumCompatible()); - this.restorer = new RocksdbRestoreTask(dbName, localCheckpointsDir, checkpointStore); - } - - public void close() { - store.close(); - } - - public void destroyLocal() { - store.close(); - - try { - // delete the checkpoints - for (File f: localCheckpointsDir.listFiles()) { - Path p = f.toPath(); - MoreFiles.deleteRecursively(f.toPath(), RecursiveDeleteOption.ALLOW_INSECURE); - } - // remove `current` symlink - new File(localDir, "current").delete(); - } catch (Exception e) { - // ignore - } - } - - public String checkpoint(String checkpointID) throws StateStoreException { - byte[] txid = checkpointID.getBytes(); - return checkpointer.checkpoint(txid); - } - - List getCheckpoints() { - return RocksCheckpointer.getCheckpoints(store.name(), checkpointStore); - } - public CheckpointInfo getLatestCheckpoint() { - List checkpoints = RocksCheckpointer.getCheckpoints(store.name(), checkpointStore); - return checkpoints.get(0); - } - - public void restore() throws Exception { - store.close(); - if (checkpointExecutor != null) { - checkpointExecutor.submit(() -> {}).get(); - } - this.init(); - } - - CheckpointMetadata restore(CheckpointInfo checkpoint) throws StateStoreException, TimeoutException { - try { - MoreFiles.deleteRecursively( - checkpoint.getCheckpointPath(localDir), - RecursiveDeleteOption.ALLOW_INSECURE); - } catch (Exception e) { - // ignore - } - - CheckpointMetadata md = checkpoint.restore(store.name(), localDir, checkpointStore); - store.close(); - store = new RocksdbKVStore<>(); - store.init(spec); - this.init(); - return md; - } - - - private static String getKey(int i) { - return String.format("key-%06d", i); - } - - private static String getValue(int i) { - return String.format("val-%06d", i); - } - - public void addNumKVs(String txId, int numKvs, int startIdx) throws StateStoreException { - for (int i = 0; i < numKvs; i++) { - String key = getKey(startIdx + i); - String val = getValue(startIdx + i); - - store.put(key, val); - } - store.put("transaction-id", txId); - store.flush(); - } - - public void addNumKVs(int numKvs, int startIdx) throws StateStoreException { - for (int i = 0; i < numKvs; i++) { - String key = getKey(startIdx + i); - String val = getValue(startIdx + i); - - store.put(key, val); - } - store.flush(); - } - - public String get(String key) { - return store.get(key); - } - - public void corruptCheckpoint(CheckpointInfo cpi) throws IOException { - File checkpointDir = cpi.getCheckpointPath(remoteCheckpointsPath.toFile()).toFile(); - - File current = new File(checkpointDir, "CURRENT"); - FileWriter w = new FileWriter(current); - w.write("MANIFEST-xxxx\n"); - w.close(); - } -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCAsyncBytesStoreImpl.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCAsyncBytesStoreImpl.java deleted file mode 100644 index 520c5e63ba1..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCAsyncBytesStoreImpl.java +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.statelib.impl.mvcc; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.io.File; -import java.net.URI; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.IntStream; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.api.kv.op.PutOp; -import org.apache.bookkeeper.api.kv.options.Options; -import org.apache.bookkeeper.api.kv.result.Code; -import org.apache.bookkeeper.api.kv.result.KeyValue; -import org.apache.bookkeeper.api.kv.result.PutResult; -import org.apache.bookkeeper.common.coder.ByteArrayCoder; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.bookkeeper.statelib.api.exceptions.MVCCStoreException; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test of {@link MVCCAsyncBytesStoreImpl}. - */ -@Slf4j -public class TestMVCCAsyncBytesStoreImpl extends TestDistributedLogBase { - - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - - private static URI uri; - private static Namespace namespace; - - @BeforeClass - public static void setupCluster() throws Exception { - TestDistributedLogBase.setupCluster(); - uri = DLMTestUtil.createDLMURI(zkPort, "/mvcc"); - conf.setPeriodicFlushFrequencyMilliSeconds(2); - conf.setWriteLockEnabled(false); - namespace = NamespaceBuilder.newBuilder() - .conf(conf) - .uri(uri) - .clientId("test-mvcc-async-store") - .build(); - } - - @AfterClass - public static void teardownCluster() throws Exception { - if (null != namespace) { - namespace.close(); - } - TestDistributedLogBase.teardownCluster(); - } - - private String streamName; - private File tempDir; - private MVCCAsyncBytesStoreImpl store; - - @Before - @Override - public void setup() throws Exception { - super.setup(); - ensureURICreated(uri); - - tempDir = testDir.newFolder(); - - store = new MVCCAsyncBytesStoreImpl( - () -> new MVCCStoreImpl<>(), - () -> namespace); - } - - private StateStoreSpec initSpec(String streamName) { - return StateStoreSpec.builder() - .name(streamName) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .stream(streamName) - .localStateStoreDir(tempDir) - .build(); - } - - @After - @Override - public void teardown() throws Exception { - if (null != streamName) { - namespace.deleteLog(streamName); - } - - if (null != store) { - store.close(); - } - super.teardown(); - } - - @Test(expected = NullPointerException.class) - public void testInitMissingStreamName() throws Exception { - this.streamName = "test-init-missing-stream-name"; - StateStoreSpec spec = StateStoreSpec.builder() - .name(streamName) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .localStateStoreDir(tempDir) - .build(); - result(store.init(spec)); - } - - @Test - public void testInit() throws Exception { - this.streamName = "test-init"; - StateStoreSpec spec = initSpec(streamName); - result(store.init(spec)); - assertTrue(store.ownWriteScheduler()); - assertFalse(store.ownReadScheduler()); - assertEquals(streamName, store.name()); - } - - // - // Put & Range Ops - // - - private byte[] getKey(int i) { - return String.format("key-%05d", i).getBytes(UTF_8); - } - - private byte[] getValue(int i) { - return String.format("value-%05d", i).getBytes(UTF_8); - } - - private List> writeKVs(int numPairs, boolean prevKv) throws Exception { - List>> results = Lists.newArrayListWithExpectedSize(numPairs); - for (int i = 0; i < numPairs; i++) { - results.add(writeKV(i, prevKv)); - } - return result(FutureUtils.collect(results)); - } - - private CompletableFuture> writeKV(int i, boolean prevKv) { - PutOp op = store.getOpFactory().newPut( - getKey(i), - getValue(i), - Options.putAndGet()); - return store.put(op).whenComplete((value, cause) -> op.close()); - } - - @Test - public void testBasicOps() throws Exception { - this.streamName = "test-basic-ops"; - StateStoreSpec spec = initSpec(streamName); - result(store.init(spec)); - - // normal put - { - assertNull(result(store.get(getKey(0)))); - result(store.put(getKey(0), getValue(0))); - assertArrayEquals(getValue(0), result(store.get(getKey(0)))); - } - - // putIfAbsent - { - // failure case - assertArrayEquals(getValue(0), result(store.putIfAbsent(getKey(0), getValue(99)))); - assertArrayEquals(getValue(0), result(store.get(getKey(0)))); - // success case - byte[] key1 = getKey(1); - assertNull(result(store.putIfAbsent(key1, getValue(1)))); - assertArrayEquals(getValue(1), result(store.get(key1))); - } - - // vPut - { - // key-not-found case - int key = 2; - int initialVal = 2; - int casVal = 99; - try { - result(store.vPut(getKey(key), getValue(initialVal), 100L)); - fail("key2 doesn't exist yet"); - } catch (MVCCStoreException e) { - assertEquals(Code.KEY_NOT_FOUND, e.getCode()); - } - // vPut(k, v, -1L) - try { - result(store.vPut(getKey(key), getValue(initialVal), -1L)); - fail("key2 doesn't exist yet"); - } catch (MVCCStoreException e) { - assertEquals(Code.KEY_NOT_FOUND, e.getCode()); - } - // put(key2, v) - assertNull(result(store.putIfAbsent(getKey(key), getValue(initialVal)))); - // vPut(key2, v, 0) - assertEquals(1L, result(store.vPut(getKey(key), getValue(casVal), 0)).longValue()); - assertArrayEquals(getValue(casVal), result(store.get(getKey(key)))); - } - - // rPut - { - // key-not-found case - int key = 3; - int initialVal = 3; - int casVal = 99; - try { - result(store.rPut(getKey(key), getValue(initialVal), 100L)); - fail("key2 doesn't exist yet"); - } catch (MVCCStoreException e) { - assertEquals(Code.KEY_NOT_FOUND, e.getCode()); - } - // vPut(k, v, -1L) - try { - result(store.rPut(getKey(key), getValue(initialVal), -1L)); - fail("key2 doesn't exist yet"); - } catch (MVCCStoreException e) { - assertEquals(Code.KEY_NOT_FOUND, e.getCode()); - } - // put(key2, v) - assertNull(result(store.putIfAbsent(getKey(key), getValue(initialVal)))); - KeyValue kv = result(store.getKeyValue(getKey(key))); - long revision = kv.modifiedRevision(); - assertArrayEquals(getValue(initialVal), kv.value()); - // vPut(key2, v, 0) - assertEquals(revision + 1, result(store.rPut(getKey(key), getValue(casVal), revision)).longValue()); - assertArrayEquals(getValue(casVal), result(store.get(getKey(key)))); - } - - // delete(k) - { - // key not found - assertNull(result(store.delete(getKey(99)))); - // key exists - int key = 0; - assertArrayEquals(getValue(key), result(store.get(getKey(key)))); - assertArrayEquals(getValue(key), result(store.delete(getKey(key)))); - assertNull(result(store.get(getKey(key)))); - } - - // delete(k, v) - { - // key not found - assertNull(result(store.delete(getKey(99)))); - // key exists - int key = 1; - assertArrayEquals(getValue(key), result(store.get(getKey(key)))); - assertFalse(result(store.delete(getKey(key), getValue(99)))); - assertArrayEquals(getValue(key), result(store.get(getKey(key)))); - assertTrue(result(store.delete(getKey(key), getValue(key)))); - assertNull(result(store.get(getKey(key)))); - } - // vDelete - { - int key = 2; - @Cleanup KeyValue kv = result(store.getKeyValue(getKey(key))); - long expectedVersion = kv.version(); - try { - result(store.vDelete(getKey(key), expectedVersion + 1)); - fail("should fail to delete a key with wrong version"); - } catch (MVCCStoreException e) { - assertEquals(Code.BAD_REVISION, e.getCode()); - } - // vDelete(k, -1L) - try { - result(store.vDelete(getKey(key), -1L)); - fail("Should fail to delete a key with version(-1)"); - } catch (MVCCStoreException e) { - assertEquals(Code.BAD_REVISION, e.getCode()); - } - // vDelete(key2, version) - @Cleanup KeyValue deletedKv = (result(store.vDelete(getKey(key), expectedVersion))); - assertNotNull(deletedKv); - assertEquals(kv.createRevision(), deletedKv.createRevision()); - assertEquals(kv.modifiedRevision(), deletedKv.modifiedRevision()); - assertEquals(kv.version(), deletedKv.version()); - assertArrayEquals(kv.value(), deletedKv.value()); - assertNull(result(store.get(getKey(key)))); - } - - // rPut - { - int key = 3; - @Cleanup KeyValue kv = result(store.getKeyValue(getKey(key))); - long expectedRevision = kv.modifiedRevision(); - try { - result(store.rDelete(getKey(key), expectedRevision + 1)); - fail("should fail to delete a key with wrong revision"); - } catch (MVCCStoreException e) { - assertEquals(Code.BAD_REVISION, e.getCode()); - } - // rDelete(k, -1L) - try { - result(store.rDelete(getKey(key), -1L)); - fail("Should fail to delete a key with revision(-1)"); - } catch (MVCCStoreException e) { - assertEquals(Code.BAD_REVISION, e.getCode()); - } - // rDelete(key2, revision) - @Cleanup KeyValue deletedKv = (result(store.rDelete(getKey(key), expectedRevision))); - assertNotNull(deletedKv); - assertEquals(kv.createRevision(), deletedKv.createRevision()); - assertEquals(kv.modifiedRevision(), deletedKv.modifiedRevision()); - assertEquals(kv.version(), deletedKv.version()); - assertArrayEquals(kv.value(), deletedKv.value()); - assertNull(result(store.get(getKey(key)))); - } - - // increment failure - { - int ki = 3; - byte[] key = getKey(ki); - result(store.put(key, getValue(ki))); - try { - result(store.increment(key, 100L)); - fail("Can't increment a non-number key"); - } catch (MVCCStoreException e) { - assertEquals(Code.ILLEGAL_OP, e.getCode()); - } - } - - // increment success - { - int ki = 4; - byte[] key = getKey(ki); - for (int i = 0; i < 5; i++) { - result(store.increment(key, 100L)); - @Cleanup KeyValue kv = result(store.getKeyValue(key)); - assertEquals(100L * (i + 1), kv.numberValue()); - } - } - } - - @Test - public void testPutGetDeleteRanges() throws Exception { - this.streamName = "test-put-kvs"; - StateStoreSpec spec = initSpec(streamName); - result(store.init(spec)); - int numPairs = 100; - List> kvs = writeKVs(numPairs, true); - assertEquals(numPairs, kvs.size()); - - for (PutResult kv : kvs) { - assertEquals(Code.OK, kv.code()); - assertNull(kv.prevKv()); - kv.close(); - } - - verifyRange(20, 70, 2, 2, 0); - - List> prevKvs = result(store.deleteRange(getKey(20), getKey(70))); - assertNotNull(prevKvs); - verifyRecords( - prevKvs, - 20, 70, - 2, 2, 0); - prevKvs.forEach(KeyValue::close); - - prevKvs = result(store.range(getKey(20), getKey(70))); - assertTrue(prevKvs.isEmpty()); - } - - private void verifyRange(int startKey, - int endKey, - int startCreateRevision, - int startModRevision, - int expectedVersion) throws Exception { - int count = endKey - startKey + 1; - List> kvs = result(store.range(getKey(startKey), getKey(endKey))); - assertEquals(count, kvs.size()); - - verifyRecords(kvs, startKey, endKey, startCreateRevision, startModRevision, expectedVersion); - - kvs.forEach(KeyValue::close); - } - - private void verifyRecords(List> kvs, - int startKey, int endKey, - int startCreateRevision, - int startModRevision, - int expectedVersion) { - int idx = startKey; - for (KeyValue record : kvs) { - assertArrayEquals(getKey(idx), record.key()); - assertArrayEquals(getValue(idx), record.value()); - // revision - starts from 1, but the first revision is used for nop barrier record. - assertEquals(idx + startCreateRevision, record.createRevision()); - assertEquals(idx + startModRevision, record.modifiedRevision()); - assertEquals(expectedVersion, record.version()); - ++idx; - } - assertEquals(endKey + 1, idx); - } - - @Test - public void testReplayJournal() throws Exception { - this.streamName = "test-replay-journal"; - StateStoreSpec spec = initSpec(streamName); - result(store.init(spec)); - - int numKvs = 10; - - // putIfAbsent - IntStream.range(0, numKvs) - .forEach(i -> { - try { - result(store.putIfAbsent(getKey(i), getValue(100 + i))); - } catch (Exception e) { - log.error("Failed to put kv pair ({})", i, e); - } - }); - - log.info("Closing the store '{}' ...", streamName); - // close the store - store.close(); - log.info("Closed the store '{}' ...", streamName); - - // open the store again to replay the journal. - store = new MVCCAsyncBytesStoreImpl( - () -> new MVCCStoreImpl<>(), - () -> namespace); - spec = StateStoreSpec.builder() - .name(streamName) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .stream(streamName) - .localStateStoreDir(testDir.newFolder()) - .build(); - result(store.init(spec)); - - // verify the key/value pairs - for (int i = 0; i < numKvs; i++) { - byte[] value = result(store.get(getKey(i))); - assertNotNull(value); - assertArrayEquals(getValue(100 + i), value); - } - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCStoreImpl.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCStoreImpl.java deleted file mode 100644 index adb023412b5..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCStoreImpl.java +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.statelib.impl.mvcc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.api.kv.op.CompareResult; -import org.apache.bookkeeper.api.kv.op.OpType; -import org.apache.bookkeeper.api.kv.op.RangeOp; -import org.apache.bookkeeper.api.kv.op.TxnOp; -import org.apache.bookkeeper.api.kv.options.Options; -import org.apache.bookkeeper.api.kv.result.Code; -import org.apache.bookkeeper.api.kv.result.DeleteResult; -import org.apache.bookkeeper.api.kv.result.KeyValue; -import org.apache.bookkeeper.api.kv.result.PutResult; -import org.apache.bookkeeper.api.kv.result.RangeResult; -import org.apache.bookkeeper.api.kv.result.Result; -import org.apache.bookkeeper.api.kv.result.TxnResult; -import org.apache.bookkeeper.common.coder.StringUtf8Coder; -import org.apache.bookkeeper.common.kv.KV; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.bookkeeper.statelib.api.exceptions.MVCCStoreException; -import org.apache.bookkeeper.statelib.api.kv.KVIterator; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test of {@link MVCCStoreImpl}. - */ -@Slf4j -public class TestMVCCStoreImpl { - - @Rule - public final TestName runtime = new TestName(); - - private File tempDir; - private StateStoreSpec spec; - private MVCCStoreImpl store; - - @Before - public void setUp() throws IOException { - tempDir = java.nio.file.Files.createTempDirectory("test").toFile(); - spec = StateStoreSpec.builder() - .name(runtime.getMethodName()) - .keyCoder(StringUtf8Coder.of()) - .valCoder(StringUtf8Coder.of()) - .localStateStoreDir(tempDir) - .stream(runtime.getMethodName()) - .build(); - store = new MVCCStoreImpl<>(); - } - - @After - public void tearDown() throws Exception { - if (null != store) { - store.close(); - } - if (null != tempDir) { - FileUtils.deleteDirectory(tempDir); - } - } - - // - // Operations - // - - - @Test - public void testGetNull() throws Exception { - store.init(spec); - assertNull(store.get("key")); - } - - @Test - public void testGetValue() throws Exception { - store.init(spec); - store.put("key", "value", 1L); - assertEquals("value", store.get("key")); - } - - @Test - public void testPutValueSmallerRevision() throws Exception { - store.init(spec); - store.put("key", "value", 2L); - assertEquals("value", store.get("key")); - try { - store.put("key", "newValue", 1L); - fail("Should fail to put a value with smaller revision"); - } catch (MVCCStoreException e) { - assertEquals(Code.SMALLER_REVISION, e.getCode()); - } - } - - private String getKey(int i) { - return String.format("key-%05d", i); - } - - private String getValue(int i) { - return String.format("value-%05d", i); - } - - private void writeKVs(int numPairs, long revision) { - for (int i = 0; i < numPairs; i++) { - store.put(getKey(i), getValue(i), revision); - } - } - - @Test - public void testAllRange() throws Exception { - store.init(spec); - writeKVs(100, 1L); - KVIterator iter = store.range( - getKey(0), - getKey(100)); - int idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(100, idx); - iter.close(); - } - - @Test - public void testSubRange() throws Exception { - store.init(spec); - writeKVs(100, 1L); - KVIterator iter = store.range( - getKey(20), - getKey(79)); - int idx = 20; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(80, idx); - iter.close(); - } - - @Test - public void testRangeOp() throws Exception { - store.init(spec); - long revision = 99L; - writeKVs(100, revision); - @Cleanup RangeOp op = store.getOpFactory().newRange( - getKey(20), - store.getOpFactory().optionFactory().newRangeOption() - .endKey(getKey(79)) - .limit(100) - .build()); - @Cleanup RangeResult result = store.range(op); - assertEquals(Code.OK, result.code()); - assertEquals(60, result.count()); - assertEquals(60, result.kvs().size()); - assertEquals(false, result.more()); - int idx = 20; - for (KeyValue record : result.kvs()) { - assertEquals(getKey(idx), record.key()); - assertEquals(getValue(idx), record.value()); - assertEquals(revision, record.createRevision()); - assertEquals(revision, record.modifiedRevision()); - assertEquals(0, record.version()); - ++idx; - } - assertEquals(80, idx); - } - - @Test - public void testRangeOpNoMoreKvs() throws Exception { - store.init(spec); - long revision = 99L; - writeKVs(100, revision); - @Cleanup RangeOp op = store.getOpFactory().newRange( - getKey(20), - store.getOpFactory().optionFactory().newRangeOption() - .endKey(getKey(99)) - .limit(100) - .build()); - @Cleanup RangeResult result = store.range(op); - assertEquals(Code.OK, result.code()); - assertEquals(80, result.count()); - assertEquals(80, result.kvs().size()); - assertEquals(false, result.more()); - int idx = 20; - for (KeyValue record : result.kvs()) { - assertEquals(getKey(idx), record.key()); - assertEquals(getValue(idx), record.value()); - assertEquals(revision, record.createRevision()); - assertEquals(revision, record.modifiedRevision()); - assertEquals(0, record.version()); - ++idx; - } - assertEquals(100, idx); - } - - @Test - public void testRangeOpHasMoreKvs() throws Exception { - store.init(spec); - long revision = 99L; - writeKVs(100, revision); - @Cleanup RangeOp op = store.getOpFactory().newRange( - getKey(20), - store.getOpFactory().optionFactory().newRangeOption() - .endKey(getKey(79)) - .limit(20) - .build()); - @Cleanup RangeResult result = store.range(op); - assertEquals(Code.OK, result.code()); - assertEquals(20, result.count()); - assertEquals(20, result.kvs().size()); - assertEquals(true, result.more()); - int idx = 20; - for (KeyValue record : result.kvs()) { - assertEquals(getKey(idx), record.key()); - assertEquals(getValue(idx), record.value()); - assertEquals(revision, record.createRevision()); - assertEquals(revision, record.modifiedRevision()); - assertEquals(0, record.version()); - ++idx; - } - assertEquals(40, idx); - } - - @Test - public void testDeleteKey() throws Exception { - store.init(spec); - store.put("key", "value", 99L); - assertEquals("value", store.get("key")); - store.delete("key", 100L); - assertNull(store.get("key")); - } - - @Test - public void testDeleteHeadRange() throws Exception { - store.init(spec); - // write 100 kvs - writeKVs(100, 99L); - // iterate all kvs - KVIterator iter = store.range( - getKey(0), getKey(100)); - int idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(100, idx); - iter.close(); - // delete range - store.deleteRange(getKey(0), getKey(20), 100L); - iter = store.range( - getKey(0), getKey(100)); - idx = 21; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(100, idx); - iter.close(); - } - - @Test - public void testDeleteTailRange() throws Exception { - store.init(spec); - // write 100 kvs - writeKVs(100, 99L); - // iterate all kvs - KVIterator iter = store.range( - getKey(0), getKey(100)); - int idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(100, idx); - iter.close(); - // delete range - store.deleteRange(getKey(10), getKey(100), 100L); - iter = store.range( - getKey(0), getKey(100)); - idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(10, idx); - iter.close(); - } - - @Test - public void testDeleteRange() throws Exception { - store.init(spec); - // write 100 kvs - writeKVs(100, 99L); - // iterate all kvs - KVIterator iter = store.range( - getKey(0), - getKey(100)); - int idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(100, idx); - iter.close(); - // delete range - store.deleteRange(getKey(10), getKey(20), 100L); - iter = store.range( - getKey(0), - getKey(100)); - idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - if (10 == idx) { - idx = 21; - } - } - assertEquals(100, idx); - iter.close(); - } - - @Test - public void testTxnCompareSuccess() throws Exception { - store.init(spec); - // write 10 kvs at revision 99L - writeKVs(20, 99L); - @Cleanup TxnOp txnOp = store.getOpFactory().newTxn() - .If( - store.getOpFactory().compareCreateRevision( - CompareResult.EQUAL, - getKey(10), - 99L)) - .Then( - store.getOpFactory().newPut( - getKey(11), - "test-value", - Options.putAndGet())) - .Else( - store.getOpFactory().newDelete( - getKey(11), - store.getOpFactory().optionFactory().newDeleteOption() - .build())) - .build(); - @Cleanup TxnResult result = store.txn(100L, txnOp); - assertEquals(Code.OK, result.code()); - assertEquals(100L, result.revision()); - assertEquals(1, result.results().size()); - assertTrue(result.isSuccess()); - Result subResult = result.results().get(0); - assertEquals(OpType.PUT, subResult.type()); - PutResult putResult = (PutResult) subResult; - KeyValue prevResult = putResult.prevKv(); - assertEquals(getKey(11), prevResult.key()); - assertEquals(getValue(11), prevResult.value()); - assertEquals(99L, prevResult.createRevision()); - assertEquals(99L, prevResult.modifiedRevision()); - assertEquals(0L, prevResult.version()); - - assertEquals("test-value", store.get(getKey(11))); - } - - - @Test - public void testTxnCompareFailure() throws Exception { - store.init(spec); - // write 10 kvs at revision 99L - writeKVs(20, 99L); - @Cleanup TxnOp txnOp = store.getOpFactory().newTxn() - .If( - store.getOpFactory().compareCreateRevision( - CompareResult.NOT_EQUAL, - getKey(10), - 99L)) - .Then( - store.getOpFactory().newPut( - getKey(11), - "test-value", - Options.putAndGet())) - .Else( - store.getOpFactory().newDelete( - getKey(11), - Options.deleteAndGet())) - .build(); - @Cleanup TxnResult result = store.txn(100L, txnOp); - assertEquals(Code.OK, result.code()); - assertEquals(100L, result.revision()); - assertEquals(1, result.results().size()); - assertFalse(result.isSuccess()); - Result subResult = result.results().get(0); - assertEquals(OpType.DELETE, subResult.type()); - DeleteResult deleteResult = (DeleteResult) subResult; - List> prevResults = deleteResult.prevKvs(); - assertEquals(1, prevResults.size()); - KeyValue prevResult = prevResults.get(0); - assertEquals(getKey(11), prevResult.key()); - assertEquals(getValue(11), prevResult.value()); - assertEquals(99L, prevResult.createRevision()); - assertEquals(99L, prevResult.modifiedRevision()); - assertEquals(0L, prevResult.version()); - - assertEquals(null, store.get(getKey(11))); - } - - @Test - public void testIncrement() throws Exception { - store.init(spec); - - for (int i = 0; i < 5; i++) { - store.increment("key", 100L, 99L + i); - Long number = store.getNumber("key"); - assertNotNull(number); - assertEquals(100L * (i + 1), number.longValue()); - } - } - - @Test - public void testIncrementFailure() throws Exception { - store.init(spec); - - store.put("key", "value", 1L); - try { - store.increment("key", 100, 2L); - fail("Should fail to increment a non-number key"); - } catch (MVCCStoreException e) { - assertEquals(Code.ILLEGAL_OP, e.getCode()); - } - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCUtils.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCUtils.java deleted file mode 100644 index 955db0e149d..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/TestMVCCUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.statelib.impl.mvcc; - -import static org.junit.Assert.assertEquals; - -import io.netty.buffer.ByteBuf; -import org.apache.bookkeeper.stream.proto.kv.store.Command; -import org.junit.Test; - -/** - * Test case for {@link MVCCUtils}. - */ -public class TestMVCCUtils { - - @Test - public void testNewLogRecordBuf() { - Command command = MVCCUtils.NOP_CMD; - ByteBuf buffer = MVCCUtils.newLogRecordBuf(command); - assertEquals(command.getSerializedSize(), buffer.readableBytes()); - Command another = MVCCUtils.newCommand(buffer); - assertEquals(command, another); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/op/proto/ProtoCompareImplTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/op/proto/ProtoCompareImplTest.java deleted file mode 100644 index 6e50bafacd1..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/mvcc/op/proto/ProtoCompareImplTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.statelib.impl.mvcc.op.proto; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import com.google.protobuf.ByteString; -import lombok.Cleanup; -import org.apache.bookkeeper.stream.proto.kv.rpc.Compare; -import org.apache.bookkeeper.stream.proto.kv.rpc.Compare.CompareResult; -import org.apache.bookkeeper.stream.proto.kv.rpc.Compare.CompareTarget; -import org.junit.Test; - -/** - * Unit test {@link ProtoCompareImpl}. - */ -public class ProtoCompareImplTest { - - private static final ByteString KEY = ByteString.copyFromUtf8("test-key"); - private static final ByteString VAL = ByteString.copyFromUtf8("test-value"); - private static final long MOD_REV = System.currentTimeMillis(); - private static final long CREATE_REV = MOD_REV + 1; - private static final long VERSION = CREATE_REV + 1; - - @Test - public void testCompareEmptyValue() { - Compare compare = Compare.newBuilder() - .setKey(KEY) - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.VALUE) - .build(); - - @Cleanup ProtoCompareImpl protoCompare = ProtoCompareImpl.newCompareOp(compare); - assertArrayEquals("test-key".getBytes(UTF_8), protoCompare.key()); - assertNull(protoCompare.value()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareResult.EQUAL, protoCompare.result()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareTarget.VALUE, protoCompare.target()); - } - - @Test - public void testCompareValue() { - Compare compare = Compare.newBuilder() - .setKey(KEY) - .setValue(VAL) - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.VALUE) - .build(); - - @Cleanup ProtoCompareImpl protoCompare = ProtoCompareImpl.newCompareOp(compare); - assertArrayEquals("test-key".getBytes(UTF_8), protoCompare.key()); - assertArrayEquals("test-value".getBytes(UTF_8), protoCompare.value()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareResult.EQUAL, protoCompare.result()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareTarget.VALUE, protoCompare.target()); - } - - @Test - public void testCompareMod() { - Compare compare = Compare.newBuilder() - .setKey(KEY) - .setModRevision(MOD_REV) - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.MOD) - .build(); - - @Cleanup ProtoCompareImpl protoCompare = ProtoCompareImpl.newCompareOp(compare); - assertArrayEquals("test-key".getBytes(UTF_8), protoCompare.key()); - assertEquals(MOD_REV, protoCompare.revision()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareResult.EQUAL, protoCompare.result()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareTarget.MOD, protoCompare.target()); - } - - @Test - public void testCompareCreate() { - Compare compare = Compare.newBuilder() - .setKey(KEY) - .setCreateRevision(CREATE_REV) - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.CREATE) - .build(); - - @Cleanup ProtoCompareImpl protoCompare = ProtoCompareImpl.newCompareOp(compare); - assertArrayEquals("test-key".getBytes(UTF_8), protoCompare.key()); - assertEquals(CREATE_REV, protoCompare.revision()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareResult.EQUAL, protoCompare.result()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareTarget.CREATE, protoCompare.target()); - } - - @Test - public void testCompareVersion() { - Compare compare = Compare.newBuilder() - .setKey(KEY) - .setVersion(VERSION) - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.VERSION) - .build(); - - @Cleanup ProtoCompareImpl protoCompare = ProtoCompareImpl.newCompareOp(compare); - assertArrayEquals("test-key".getBytes(UTF_8), protoCompare.key()); - assertEquals(VERSION, protoCompare.revision()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareResult.EQUAL, protoCompare.result()); - assertEquals(org.apache.bookkeeper.api.kv.op.CompareTarget.VERSION, protoCompare.target()); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/RocksUtilsTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/RocksUtilsTest.java deleted file mode 100644 index a7242f187c0..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/RocksUtilsTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.impl.rocksdb; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.File; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.rocksdb.AbstractImmutableNativeReference; - -/** - * Unit test of {@link RocksUtils}. - */ -public class RocksUtilsTest { - - @Rule - public final TestName runtime = new TestName(); - - private String testPrefix; - - @Before - public void setUp() { - this.testPrefix = "path/to/" + runtime.getMethodName(); - } - - @Test - public void testCloseNull() { - RocksUtils.close(null); - assertTrue(true); - } - - @Test - public void testClose() { - AbstractImmutableNativeReference ref = mock(AbstractImmutableNativeReference.class); - RocksUtils.close(ref); - verify(ref, times(1)).close(); - } - - @Test - public void testIsSstFile() { - assertTrue(RocksUtils.isSstFile(new File("test.sst"))); - } - - @Test - public void testIsNotSstFile() { - assertFalse(RocksUtils.isSstFile(new File("test.sst1"))); - } - - @Test - public void testGetDestCheckpointsPath() { - Assert.assertEquals(testPrefix + "/checkpoints", RocksUtils.getDestCheckpointsPath(testPrefix)); - } - - @Test - public void testGetDestCheckpointPath() { - Assert.assertEquals( - testPrefix + "/checkpoints/" + runtime.getMethodName(), - RocksUtils.getDestCheckpointPath(testPrefix, runtime.getMethodName())); - } - - @Test - public void testGetDestCheckpointMetadataPath() { - Assert.assertEquals( - testPrefix + "/checkpoints/" + runtime.getMethodName() + "/metadata", - RocksUtils.getDestCheckpointMetadataPath(testPrefix, runtime.getMethodName())); - } - - @Test - public void testGetDestSstsPath() { - Assert.assertEquals( - testPrefix + "/ssts", - RocksUtils.getDestSstsPath(testPrefix)); - } - - @Test - public void testGetDestSStPathFile() { - Assert.assertEquals( - testPrefix + "/ssts/" + runtime.getMethodName(), - RocksUtils.getDestSstPath(testPrefix, new File("/path/to/" + runtime.getMethodName()))); - } - - @Test - public void testGetDestSStPath() { - Assert.assertEquals( - testPrefix + "/ssts/" + runtime.getMethodName(), - RocksUtils.getDestSstPath(testPrefix, runtime.getMethodName())); - } - - @Test - public void testGetDestTempSstPath() { - Assert.assertEquals( - testPrefix + "/checkpoints/" + runtime.getMethodName() + "/" + runtime.getMethodName() + ".sst", - RocksUtils.getDestTempSstPath( - testPrefix, - runtime.getMethodName(), - new File("/path/to/" + runtime.getMethodName() + ".sst"))); - } - - @Test - public void testGetDestPath() { - Assert.assertEquals( - testPrefix + "/checkpoints/" + runtime.getMethodName() + "/" + runtime.getMethodName() + ".sst", - RocksUtils.getDestTempSstPath( - testPrefix, - runtime.getMethodName(), - new File("/path/to/" + runtime.getMethodName() + ".sst"))); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/RocksCheckpointerTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/RocksCheckpointerTest.java deleted file mode 100644 index b880ac1b94b..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/RocksCheckpointerTest.java +++ /dev/null @@ -1,745 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Sets; -import com.google.common.io.ByteStreams; -import com.google.common.io.MoreFiles; -import com.google.common.io.RecursiveDeleteOption; -import java.io.File; -import java.io.FileInputStream; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Paths; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.coder.StringUtf8Coder; -import org.apache.bookkeeper.common.kv.KV; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.bookkeeper.statelib.api.checkpoint.CheckpointStore; -import org.apache.bookkeeper.statelib.api.exceptions.StateStoreException; -import org.apache.bookkeeper.statelib.api.kv.KVIterator; -import org.apache.bookkeeper.statelib.impl.kv.RocksdbKVStore; -import org.apache.bookkeeper.statelib.impl.kv.TestStateStore; -import org.apache.bookkeeper.statelib.impl.rocksdb.RocksUtils; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.fs.FSCheckpointManager; -import org.apache.bookkeeper.stream.proto.kv.store.CheckpointMetadata; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; -import org.mockito.Mockito; -import org.rocksdb.Checkpoint; - -/** - * Unit test of {@link RocksCheckpointer}. - */ -@Slf4j -public class RocksCheckpointerTest { - - @Rule - public final TestName runtime = new TestName(); - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - - private File localDir; - private File localCheckpointsDir; - private File remoteDir; - private StateStoreSpec spec; - private RocksdbKVStore store; - private CheckpointStore checkpointStore; - - @Before - public void setUp() throws Exception { - localDir = testDir.newFolder("local"); - localCheckpointsDir = new File(localDir, "checkpoints"); - assertTrue( - "Not able to create checkpoints directory", - localCheckpointsDir.mkdir()); - remoteDir = testDir.newFolder("remote"); - - checkpointStore = new FSCheckpointManager(remoteDir); - - spec = StateStoreSpec.builder() - .name(runtime.getMethodName()) - .keyCoder(StringUtf8Coder.of()) - .valCoder(StringUtf8Coder.of()) - .localStateStoreDir(localDir) - .stream(runtime.getMethodName()) - .build(); - store = new RocksdbKVStore<>(); - store.init(spec); - } - - @After - public void tearDown() throws Exception { - if (null != store) { - store.close(); - } - if (null != checkpointStore) { - checkpointStore.close(); - } - } - - private static String getKey(int i) { - return String.format("key-%06d", i); - } - - private static String getValue(int i) { - return String.format("val-%06d", i); - } - - private void writeNumKvs(int numKvs, int startIdx) throws Exception { - for (int i = 0; i < numKvs; i++) { - String key = getKey(startIdx + i); - String val = getValue(startIdx + i); - - store.put(key, val); - } - store.flush(); - } - - private void verifyNumKvs(int expectedNumKvs) throws Exception { - try (KVIterator iter = store.range(null, null)) { - int idx = 0; - while (iter.hasNext()) { - KV kv = iter.next(); - assertEquals(getKey(idx), kv.key()); - assertEquals(getValue(idx), kv.value()); - ++idx; - } - assertEquals(expectedNumKvs, idx); - } - } - - private void verifyCheckpointMetadata(File checkpointedDir, - CheckpointMetadata metadata) { - List files = CheckpointFile.list(checkpointedDir); - assertNotNull(files); - assertEquals(files.size(), metadata.getFileInfosCount()); - - Set localFiles = Sets.newHashSet(files); - Set metadataFiles = metadata.getFileInfosList() - .stream() - .map(f -> CheckpointFile.builder() - .file(checkpointedDir, f.getName()) - .computeChecksum() - .build()) - .collect(Collectors.toSet()); - - assertEquals(localFiles, metadataFiles); - } - - private void verifyRemoteFiles(String checkpointId, File checkpointedDir) throws Exception { - List files = CheckpointFile.list(checkpointedDir); - assertNotNull(files); - - for (CheckpointFile file : files) { - String remoteFile = file.getRemotePath(store.name(), checkpointId, true); - verifyRemoteFile(remoteFile, file.getFile()); - } - } - - private void verifyRemoteFile(String remoteFile, File localFile) throws Exception { - assertEquals(checkpointStore.getFileLength(remoteFile), localFile.length()); - - @Cleanup InputStream remoteIs = checkpointStore.openInputStream(remoteFile); - @Cleanup InputStream localIs = new FileInputStream(localFile); - - long numBytesToCompare = localFile.length(); - - while (numBytesToCompare > 0L) { - int numBytesToRead = (int) Math.min(numBytesToCompare, 1024); - byte[] localBytes = new byte[numBytesToRead]; - byte[] remoteBytes = new byte[numBytesToRead]; - - ByteStreams.readFully(localIs, localBytes); - ByteStreams.readFully(remoteIs, remoteBytes); - assertArrayEquals(localBytes, remoteBytes); - - numBytesToCompare -= numBytesToRead; - } - } - - private List createMultipleCheckpoints(int numCheckpoints, - boolean removeLocalCheckpointAfterCheckpoint, - boolean removeRemoteCheckpointsAfterCheckpoint) - throws Exception { - List checkpointIds = new ArrayList<>(numCheckpoints); - try (RocksCheckpointer checkpointer = new RocksCheckpointer( - store.name(), - localDir, - store.getDb(), - checkpointStore, - removeLocalCheckpointAfterCheckpoint, - removeRemoteCheckpointsAfterCheckpoint, - true, - false)) { - int idx = 0; - for (int i = 0; i < numCheckpoints; i++) { - writeNumKvs(100, idx); - checkpointIds.add(createCheckpoint(checkpointer, i)); - idx += 100; - } - } - return checkpointIds; - } - - private String createCheckpoint(RocksCheckpointer checkpointer, - int checkpointIdx) throws StateStoreException { - byte[] txid = ("checkpoint-" + checkpointIdx).getBytes(UTF_8); - return checkpointer.checkpointAtTxid(txid); - } - - /** - * Basic test. - * - *

- checkpoint a local state store to a remote checkpoint store - * - restore checkpoint from the remote checkpoint store - * - verify the restored local state store is correct - */ - @Test - public void testCheckpointRestore() throws Exception { - final int numKvs = 100; - final String dbName = runtime.getMethodName(); - final byte[] txid = runtime.getMethodName().getBytes(UTF_8); - - // first prepare rocksdb with 100 kvs; - writeNumKvs(numKvs, 0); - - Checkpoint checkpoint = Checkpoint.create(store.getDb()); - - // checkpoint - RocksdbCheckpointTask checkpointTask = new RocksdbCheckpointTask( - dbName, - checkpoint, - localCheckpointsDir, - checkpointStore, - false, - false, - true, - false); - - String checkpointId = checkpointTask.checkpoint(txid); - // checkpoint directory exists - File checkpointedDir = new File(localCheckpointsDir, checkpointId); - assertTrue( - "local checkpointed dir " + checkpointedDir + " doesn't exists when `removeLocalCheckpoints` is false", - checkpointedDir.exists()); - - // remote checkpoint metadata file exists - String checkpointMetadataFile = RocksUtils.getDestCheckpointMetadataPath(store.name(), checkpointId); - assertTrue(checkpointStore.fileExists(checkpointMetadataFile)); - int fileLen = (int) checkpointStore.getFileLength(checkpointMetadataFile); - byte[] checkpointMetadataBytes = new byte[fileLen]; - @Cleanup InputStream fileIn = checkpointStore.openInputStream(checkpointMetadataFile); - ByteStreams.readFully(fileIn, checkpointMetadataBytes); - - // verify the checkpointed metadata exists - CheckpointMetadata metadata = CheckpointMetadata.parseFrom(checkpointMetadataBytes); - assertArrayEquals(txid, metadata.getTxid().toByteArray()); - verifyCheckpointMetadata(checkpointedDir, metadata); - verifyRemoteFiles(checkpointId, checkpointedDir); - - store.close(); - - // remove local checkpointed dir - MoreFiles.deleteRecursively( - Paths.get(checkpointedDir.getAbsolutePath()), - RecursiveDeleteOption.ALLOW_INSECURE); - assertFalse(checkpointedDir.exists()); - - // restore the checkpoint - RocksdbRestoreTask restoreTask = new RocksdbRestoreTask( - dbName, - localCheckpointsDir, - checkpointStore); - restoreTask.restore(checkpointId, metadata); - assertTrue(checkpointedDir.exists()); - - // verify the content - verifyCheckpointMetadata(checkpointedDir, metadata); - verifyRemoteFiles(checkpointId, checkpointedDir); - - // make sure all the kvs are readable - store = new RocksdbKVStore<>(); - store.init(spec); - - verifyNumKvs(numKvs); - } - - @Test - public void testRestoreCleanupCheckpoints() throws Exception { - // create 3 checkpoints and leave them locally - List checkpointIds = createMultipleCheckpoints(3, false, false); - store.close(); - - List remoteCheckpoints = checkpointStore.listFiles(RocksUtils.getDestCheckpointsPath(store.name())); - assertEquals(checkpointIds.size(), remoteCheckpoints.size()); - - for (String checkpoint : checkpointIds) { - assertTrue(remoteCheckpoints.contains(checkpoint)); - assertTrue(new File(localCheckpointsDir, checkpoint).exists()); - } - - // restore from checkpoints - CheckpointMetadata metadata = RocksCheckpointer.restore( - store.name(), - localDir, - checkpointStore); - assertNotNull(metadata); - assertArrayEquals("checkpoint-2".getBytes(UTF_8), metadata.getTxid().toByteArray()); - - for (int i = 0; i < 3; i++) { - String checkpoint = checkpointIds.get(i); - if (i == 2) { - assertTrue(new File(localCheckpointsDir, checkpoint).exists()); - } else { - assertFalse(new File(localCheckpointsDir, checkpoint).exists()); - } - assertTrue( - checkpointStore.fileExists(RocksUtils.getDestCheckpointPath(store.name(), checkpoint))); - } - - // restore from the latest checkpoint - store = new RocksdbKVStore<>(); - store.init(spec); - - verifyNumKvs(300); - } - @Test - public void testCheckpointOrder() throws Exception { - List checkpointIds = createMultipleCheckpoints(3, false, false); - - List checkpoints = RocksCheckpointer.getCheckpoints(store.name(), checkpointStore); - int totalCheckpoints = checkpoints.size(); - // there is an additional null checkpoint - assertTrue(checkpoints.size() == checkpointIds.size() + 1); - - // Last checkpoint should be null checkpoint - assertTrue(checkpoints.get(totalCheckpoints - 1).getMetadata() == null); - - // checkpoints are in reverse order - for (int i = 0; i < checkpointIds.size(); i++) { - assertEquals(checkpointIds.get(i), checkpoints.get(totalCheckpoints - 2 - i).getId()); - } - } - - InputStream getBlockedStream(TestStateStore testStore, String path, Duration blockFor) throws IOException { - InputStream stream = testStore.getCheckpointStore().openInputStream(path); - - - FilterInputStream res = new FilterInputStream(stream) { - @Override - public synchronized int read(byte[] b, int off, int len) throws IOException { - try { - Thread.sleep(blockFor.toMillis()); - } catch (InterruptedException e) { - } - return super.read(b, off, len); - } - }; - return res; - - } - - @Test(timeout = 20000) - public void testRestoreBlockedSlow() throws Exception { - final int numKvs = 100; - TestStateStore testStore = Mockito.spy(new TestStateStore( - runtime.getMethodName(), localDir, remoteDir, true, false)); - - store.close(); - - testStore.enableCheckpoints(true); - testStore.setCheckpointRestoreIdleWait(Duration.ofSeconds(3)); - - testStore.init(); - - testStore.addNumKVs("transaction-1", numKvs, 0); - // create base checkpoint - String baseCheckpoint = testStore.checkpoint("checkpoint-1"); - testStore.close(); - - String dbName = runtime.getMethodName(); - - CheckpointInfo checkpoint = testStore.getLatestCheckpoint(); - CheckpointStore mockCheckpointStore = Mockito.spy(testStore.getCheckpointStore()); - File dbPath = localDir; - - List files = CheckpointFile.list(testStore.getLocalCheckpointsDir(), - checkpoint.getMetadata()); - String testFile = files.get(0).getRemotePath(dbName, checkpoint.getId(), true); - - // We wait for 10 sec for some data to show up. We will add the data after 8 sec. So the restore should succeed. - Mockito.doReturn(getBlockedStream(testStore, testFile, Duration.ofSeconds(2))) - .when(mockCheckpointStore) - .openInputStream(testFile); - - Mockito.doReturn(mockCheckpointStore).when(testStore).newCheckpointStore(); - - try { - testStore.restore(); - } catch (Exception e) { - fail("restore should succeed from slow stream"); - } - } - - @Test(timeout = 20000) - public void testRestoreBlockedTimeout() throws Exception { - final int numKvs = 100; - TestStateStore testStore = Mockito.spy(new TestStateStore( - runtime.getMethodName(), localDir, remoteDir, true, false)); - - store.close(); - - testStore.enableCheckpoints(true); - testStore.setCheckpointRestoreIdleWait(Duration.ofSeconds(10)); - - testStore.init(); - - testStore.addNumKVs("transaction-1", numKvs, 0); - // create base checkpoint - String baseCheckpoint = testStore.checkpoint("checkpoint-1"); - testStore.close(); - - String dbName = runtime.getMethodName(); - - CheckpointInfo checkpoint = testStore.getLatestCheckpoint(); - CheckpointStore mockCheckpointStore = Mockito.spy(testStore.getCheckpointStore()); - File dbPath = localDir; - - List files = CheckpointFile.list(testStore.getLocalCheckpointsDir(), - checkpoint.getMetadata()); - String testFile = files.get(0).getRemotePath(dbName, checkpoint.getId(), true); - - Mockito.doReturn(getBlockedStream(testStore, testFile, Duration.ofSeconds(20))) - .when(mockCheckpointStore) - .openInputStream(testFile); - - Mockito.doReturn(mockCheckpointStore).when(testStore).newCheckpointStore(); - - try { - testStore.restore(); - fail("should Fail to restore from a blocked stream"); - } catch (Exception e) { - - } - } - - @Test - public void testStaleSSTFile() throws Exception { - final int numKvs = 100; - TestStateStore testStore = new TestStateStore( - runtime.getMethodName(), localDir, remoteDir, true, false); - - store.close(); - - testStore.enableCheckpoints(true); - testStore.init(); - - testStore.addNumKVs("transaction-1", numKvs, 0); - // create base checkpoint - String baseCheckpoint = testStore.checkpoint("checkpoint-1"); - testStore.restore(); - - testStore.addNumKVs("transaction-2", numKvs, 100); - // create failed checkpoint - String failedCheckpoint = testStore.checkpoint("checkpoint-2"); - // Remove metadata from the checkpoint to signal failure - - CheckpointInfo checkpoint = testStore.getLatestCheckpoint(); - testStore.corruptCheckpoint(checkpoint); - - // restore : this should restore from base checkpoint - testStore.destroyLocal(); - testStore.restore(); - assertEquals("transaction-1", testStore.get("transaction-id")); - - testStore.addNumKVs("transaction-3", numKvs * 3, 200); - // create another test checkpoint - String newCheckpoint = testStore.checkpoint("checkpoint-3"); - - // Ensure latest checkpoint can be restored. - testStore.destroyLocal(); - testStore.restore(); - assertEquals("transaction-3", testStore.get("transaction-id")); - } - - @Test - public void testRestoreDowngradeWithoutChecksumCompatible() throws Exception { - store.close(); - TestStateStore testStore = new TestStateStore( - runtime.getMethodName(), localDir, remoteDir, true, false); - - testStore.checkpointChecksumCompatible(true); - downgradeWithoutChecksum(testStore); - // if compatible then downgrade should work - assertEquals("transaction-1", testStore.get("transaction-id")); - } - - @Test - public void testRestoreDowngradeWithoutChecksumNonCompatible() throws Exception { - store.close(); - TestStateStore testStore = new TestStateStore( - runtime.getMethodName(), localDir, remoteDir, true, false); - - testStore.checkpointChecksumCompatible(false); - try { - downgradeWithoutChecksum(testStore); - fail("Downgrade without checksum compatible set should fail"); - } catch (StateStoreException sse) { - } - } - - private String downgradeWithoutChecksum(TestStateStore testStore) throws Exception { - final int numKvs = 100; - testStore.init(); - - testStore.addNumKVs("transaction-1", numKvs, 0); - String checkpoint1 = testStore.checkpoint("checkpoint-1"); - - assertEquals("transaction-1", testStore.get("transaction-id")); - - // restore without checksum information - RocksdbRestoreTask restoreTask = getDowngradeRestoreTask(); - - testStore.destroyLocal(); - CheckpointInfo latest = testStore.getLatestCheckpoint(); - - latest.restore(localDir, restoreTask); - - testStore.init(); - return checkpoint1; - } - - private RocksdbRestoreTask getDowngradeRestoreTask() { - return new RocksdbRestoreTask( - runtime.getMethodName(), localCheckpointsDir, checkpointStore) { - - @Override - protected List getCheckpointFiles(File checkpointedDir, CheckpointMetadata metadata) { - // ignore the checksum info in metadata - return metadata.getFilesList().stream() - .map(f -> CheckpointFile.builder() - .file(checkpointedDir, f) - .build()) - .collect(Collectors.toList()); - } - }; - } - - @Test - public void testRestoreOldCheckpointWithoutChecksum() throws Exception { - final int numKvs = 100; - TestStateStore testStore = new TestStateStore( - runtime.getMethodName(), localDir, remoteDir, true, false); - - store.close(); - - testStore.enableCheckpoints(true); - testStore.checkpointChecksumEnable(false); - testStore.init(); - - testStore.addNumKVs("transaction-1", numKvs, 0); - String checkpoint1 = testStore.checkpoint("checkpoint-1"); - - - testStore.checkpointChecksumEnable(true); - // restore : this should restore to checkpoint-2 - testStore.destroyLocal(); - testStore.restore(); - assertEquals("transaction-1", testStore.get("transaction-id")); - } - - @Test - public void testRestoreCheckpointMissingLocally() throws Exception { - // create 3 checkpoints and leave them locally - List checkpointIds = createMultipleCheckpoints(3, false, false); - store.close(); - - List remoteCheckpoints = checkpointStore.listFiles(RocksUtils.getDestCheckpointsPath(store.name())); - assertEquals(checkpointIds.size(), remoteCheckpoints.size()); - - for (String checkpoint : checkpointIds) { - assertTrue(remoteCheckpoints.contains(checkpoint)); - assertTrue(new File(localCheckpointsDir, checkpoint).exists()); - } - - // remove a local checkpoint directory - MoreFiles.deleteRecursively( - Paths.get(localCheckpointsDir.getAbsolutePath(), checkpointIds.get(2)), - RecursiveDeleteOption.ALLOW_INSECURE); - - // restore from checkpoints - CheckpointMetadata metadata = RocksCheckpointer.restore( - store.name(), - localDir, - checkpointStore); - assertNotNull(metadata); - assertArrayEquals("checkpoint-2".getBytes(UTF_8), metadata.getTxid().toByteArray()); - - for (int i = 0; i < 3; i++) { - String checkpoint = checkpointIds.get(i); - if (i == 2) { - assertTrue(new File(localCheckpointsDir, checkpoint).exists()); - } else { - assertFalse(new File(localCheckpointsDir, checkpoint).exists()); - } - assertTrue( - checkpointStore.fileExists(RocksUtils.getDestCheckpointPath(store.name(), checkpoint))); - } - - // restore from the latest checkpoint - store = new RocksdbKVStore<>(); - store.init(spec); - - verifyNumKvs(300); - } - - @Test - public void testRestoreLocalCheckpointCorrupted() throws Exception { - // create 1 checkpoints and leave them locally - List checkpointIds = createMultipleCheckpoints(1, false, false); - store.close(); - - List remoteCheckpoints = checkpointStore.listFiles(RocksUtils.getDestCheckpointsPath(store.name())); - assertEquals(checkpointIds.size(), remoteCheckpoints.size()); - - for (String checkpoint : checkpointIds) { - assertTrue(remoteCheckpoints.contains(checkpoint)); - assertTrue(new File(localCheckpointsDir, checkpoint).exists()); - } - - // remove a local checkpoint directory - File[] files = new File(localCheckpointsDir, checkpointIds.get(0)).listFiles(); - for (int i = 0; i < files.length / 2; i++) { - assertTrue(files[i].delete()); - } - - // restore from checkpoints - CheckpointMetadata metadata = RocksCheckpointer.restore( - store.name(), - localDir, - checkpointStore); - assertNotNull(metadata); - assertArrayEquals("checkpoint-0".getBytes(UTF_8), metadata.getTxid().toByteArray()); - - String checkpoint = checkpointIds.get(0); - assertTrue(new File(localCheckpointsDir, checkpoint).exists()); - assertTrue( - checkpointStore.fileExists(RocksUtils.getDestCheckpointPath(store.name(), checkpoint))); - - // restore from the latest checkpoint - store = new RocksdbKVStore<>(); - store.init(spec); - - verifyNumKvs(100); - } - - /* - Bookie can crash or get killed by an operator/automation at any point for any reason. - This test covers the situation when this happens mid-checkpoint. - */ - @Test - public void testCheckpointRestoreAfterCrash() throws Exception { - - final int numGoodCheckpoints = 3; - createMultipleCheckpoints(numGoodCheckpoints, false, false); - - final int numKvs = 100; - final String dbName = runtime.getMethodName(); - final byte[] txid = runtime.getMethodName().getBytes(UTF_8); - - // first prepare rocksdb with 100 kvs; - writeNumKvs(numKvs, 100 * numGoodCheckpoints); - - // create a checkpoint with corrupt metadata - Checkpoint checkpoint = Checkpoint.create(store.getDb()); - - // checkpoint - RocksdbCheckpointTask checkpointTask = new RocksdbCheckpointTask( - dbName, - checkpoint, - localCheckpointsDir, - checkpointStore, - false, - false, - true, - false); - - // let's simulate the crash. - // crash happens after the createDirectories() succeeded but before - // the finalizeCheckpoint() completes. - final AtomicReference idRef = new AtomicReference<>(); - checkpointTask.setInjectedError((id) -> { - idRef.set(id); - throw new RuntimeException("test"); - }); - - try { - checkpointTask.checkpoint(txid); - fail("expected RuntimeException"); - } catch (RuntimeException se) { - // noop - // in real life case ths is simply crash, - // so "finally" at the checkpoint() won't run either - } - - // remove local checkpointed dir - File checkpointedDir = new File(localCheckpointsDir, idRef.get()); - MoreFiles.deleteRecursively( - Paths.get(checkpointedDir.getAbsolutePath()), - RecursiveDeleteOption.ALLOW_INSECURE); - assertFalse(checkpointedDir.exists()); - store.close(); - - // restore the checkpoint - RocksCheckpointer.restore(dbName, localCheckpointsDir, checkpointStore); - - // al of the following succeeds if the exception from RocksCheckpointer.restore - // is ignored - - // make sure all the kvs are readable - store = new RocksdbKVStore<>(); - store.init(spec); - - verifyNumKvs((numGoodCheckpoints + 1) * numKvs); - writeNumKvs(numKvs, (numGoodCheckpoints + 1) * numKvs); - verifyNumKvs((numGoodCheckpoints + 2) * numKvs); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/dlog/DLCheckpointStoreTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/dlog/DLCheckpointStoreTest.java deleted file mode 100644 index 0ef2a4ea6f6..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/dlog/DLCheckpointStoreTest.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.dlog; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import com.google.common.io.ByteStreams; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.nio.file.FileAlreadyExistsException; -import java.util.Collections; -import java.util.List; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.fs.FSCheckpointManager; -import org.apache.distributedlog.DLMTestUtil; -import org.apache.distributedlog.DistributedLogConfiguration; -import org.apache.distributedlog.TestDistributedLogBase; -import org.apache.distributedlog.api.namespace.Namespace; -import org.apache.distributedlog.api.namespace.NamespaceBuilder; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test of {@link FSCheckpointManager}. - */ -public class DLCheckpointStoreTest extends TestDistributedLogBase { - - private static final byte[] TEST_BYTES = "dlog-checkpoint-manager".getBytes(UTF_8); - - @Rule - public final TestName runtime = new TestName(); - - private URI uri; - private Namespace namespace; - private DLCheckpointStore store; - - @BeforeClass - public static void setupDL() throws Exception { - setupCluster(); - } - - @AfterClass - public static void teardownDL() throws Exception { - teardownCluster(); - } - - @Before - public void setUp() throws Exception { - this.uri = DLMTestUtil.createDLMURI(zkPort, "/" + runtime.getMethodName()); - ensureURICreated(this.uri); - this.namespace = NamespaceBuilder.newBuilder() - .conf(new DistributedLogConfiguration()) - .uri(uri) - .build(); - this.store = new DLCheckpointStore(namespace); - } - - @After - public void tearDown() throws Exception { - if (null != store) { - store.close(); - } - } - - @Test - public void testListFilesEmpty() throws Exception { - // create a dummy log stream to ensure "dir" exists - namespace.createLog(runtime.getMethodName()); - assertTrue(store.listFiles(runtime.getMethodName()).isEmpty()); - } - - @Test - public void testListFilesNotFound() throws Exception { - assertTrue(store.listFiles(runtime.getMethodName()).isEmpty()); - } - - @Test - public void testListFiles() throws Exception { - int numFiles = 3; - List expectedFiles = Lists.newArrayListWithExpectedSize(3); - - namespace.createLog(runtime.getMethodName()); - for (int i = 0; i < numFiles; ++i) { - String filename = runtime.getMethodName() + "-" + i; - expectedFiles.add(filename); - namespace.createLog(runtime.getMethodName() + "/" + filename); - } - List files = store.listFiles(runtime.getMethodName()); - Collections.sort(files); - - assertEquals(expectedFiles, files); - } - - @Test - public void testFileExists() throws Exception { - namespace.createLog(runtime.getMethodName() + "/test"); - assertTrue(store.fileExists(runtime.getMethodName() + "/test")); - assertFalse(store.fileExists(runtime.getMethodName() + "/test2")); - } - - @Test - public void testFileRename() throws Exception { - namespace.createLog("src"); - namespace.createLog("dest"); - - String srcFilePath = "src/" + runtime.getMethodName(); - String destFilePath = "dest/" + runtime.getMethodName(); - OutputStream os = store.openOutputStream(srcFilePath); - os.write(TEST_BYTES); - os.flush(); - os.close(); - - store.rename(srcFilePath, destFilePath); - assertTrue(store.fileExists(destFilePath)); - assertFalse(store.fileExists(srcFilePath)); - - assertEquals(TEST_BYTES.length, store.getFileLength(destFilePath)); - - try (InputStream is = store.openInputStream(destFilePath)) { - byte[] readBytes = new byte[TEST_BYTES.length]; - ByteStreams.readFully(is, readBytes); - - assertArrayEquals(TEST_BYTES, readBytes); - } - } - - @Test - public void testFileRenameDirNotExists() throws Exception { - namespace.createLog("src"); - assertFalse(store.fileExists("dest")); - - String srcFilePath = "src/" + runtime.getMethodName(); - String destFilePath = "dest/" + runtime.getMethodName(); - - assertFalse(store.fileExists(srcFilePath)); - - OutputStream os = store.openOutputStream(srcFilePath); - os.write(TEST_BYTES); - os.flush(); - os.close(); - - // rename will automatically create stream path in dlog - store.rename(srcFilePath, destFilePath); - assertTrue(store.fileExists(destFilePath)); - assertFalse(store.fileExists(srcFilePath)); - - assertEquals(TEST_BYTES.length, store.getFileLength(destFilePath)); - - try (InputStream is = store.openInputStream(destFilePath)) { - byte[] readBytes = new byte[TEST_BYTES.length]; - ByteStreams.readFully(is, readBytes); - - assertArrayEquals(TEST_BYTES, readBytes); - } - } - - @Test - public void testFileRenameFileExists() throws Exception { - namespace.createLog("src"); - assertFalse(store.fileExists("dest")); - - String srcFilePath = "src/" + runtime.getMethodName(); - String destFilePath = "dest/" + runtime.getMethodName(); - namespace.createLog(destFilePath); - assertTrue(store.fileExists(destFilePath)); - - assertFalse(store.fileExists(srcFilePath)); - - OutputStream os = store.openOutputStream(srcFilePath); - os.write(TEST_BYTES); - os.flush(); - os.close(); - - assertTrue(store.fileExists(srcFilePath)); - - try { - store.rename(srcFilePath, destFilePath); - fail("Should fail to rename if the dest dir doesn't exist"); - } catch (FileAlreadyExistsException e) { - // expected - } - assertTrue(store.fileExists(destFilePath)); - assertTrue(store.fileExists(srcFilePath)); - assertEquals(0, store.getFileLength(destFilePath)); - } - - @Test - public void testDelete() throws Exception { - int numFiles = 3; - List expectedFiles = Lists.newArrayListWithExpectedSize(3); - - namespace.createLog(runtime.getMethodName()); - for (int i = 0; i < numFiles; ++i) { - String filename = runtime.getMethodName() + "-" + i; - expectedFiles.add(filename); - namespace.createLog(runtime.getMethodName() + "/" + filename); - } - List files = store.listFiles(runtime.getMethodName()); - Collections.sort(files); - - assertEquals(expectedFiles, files); - - store.delete(runtime.getMethodName()); - - assertFalse(store.fileExists(runtime.getMethodName())); - } - - @Test - public void testDeleteRecursively() throws Exception { - int numFiles = 3; - List expectedFiles = Lists.newArrayListWithExpectedSize(3); - - namespace.createLog(runtime.getMethodName()); - for (int i = 0; i < numFiles; ++i) { - String filename = runtime.getMethodName() + "-" + i; - expectedFiles.add(filename); - namespace.createLog(runtime.getMethodName() + "/" + filename); - } - List files = store.listFiles(runtime.getMethodName()); - Collections.sort(files); - - assertEquals(expectedFiles, files); - - store.delete(runtime.getMethodName()); - - assertFalse(store.fileExists(runtime.getMethodName())); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/fs/FSCheckpointManagerTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/fs/FSCheckpointManagerTest.java deleted file mode 100644 index 0db780beae4..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/impl/rocksdb/checkpoint/fs/FSCheckpointManagerTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.fs; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.io.File; -import java.io.OutputStream; -import java.nio.file.NoSuchFileException; -import java.util.Collections; -import java.util.List; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; - -/** - * Unit test of {@link FSCheckpointManager}. - */ -public class FSCheckpointManagerTest { - - private static final byte[] TEST_BYTES = "fs-checkpoint-manager".getBytes(UTF_8); - - @Rule - public final TemporaryFolder testFolder = new TemporaryFolder(); - @Rule - public final TestName runtime = new TestName(); - - private File rootDir; - private FSCheckpointManager cm; - - @Before - public void setUp() throws Exception { - this.rootDir = testFolder.newFolder("checkpoints"); - this.cm = new FSCheckpointManager(rootDir); - } - - @Test - public void testListFilesEmpty() throws Exception { - new File(rootDir, runtime.getMethodName()).mkdir(); - assertTrue(cm.listFiles(runtime.getMethodName()).isEmpty()); - } - - @Test - public void testListFilesNotFound() throws Exception { - assertTrue(cm.listFiles(runtime.getMethodName()).isEmpty()); - } - - @Test - public void testListFiles() throws Exception { - int numFiles = 3; - List expectedFiles = Lists.newArrayListWithExpectedSize(3); - - File testDir = new File(rootDir, runtime.getMethodName()); - testDir.mkdir(); - for (int i = 0; i < numFiles; ++i) { - String filename = runtime.getMethodName() + "-" + i; - expectedFiles.add(filename); - new File(testDir, filename).mkdir(); - } - List files = cm.listFiles(runtime.getMethodName()); - Collections.sort(files); - - assertEquals(expectedFiles, files); - } - - @Test - public void testFileExists() throws Exception { - File testDir = new File(new File(rootDir, runtime.getMethodName()), "test"); - testDir.mkdirs(); - assertTrue(cm.fileExists(runtime.getMethodName() + "/test")); - assertFalse(cm.fileExists(runtime.getMethodName() + "/test2")); - } - - @Test - public void testFileRename() throws Exception { - File srcDir = new File(rootDir, "src"); - srcDir.mkdir(); - File destDir = new File(rootDir, "dest"); - destDir.mkdir(); - - String srcFilePath = "src/" + runtime.getMethodName(); - String destFilePath = "dest/" + runtime.getMethodName(); - OutputStream os = cm.openOutputStream(srcFilePath); - os.write(TEST_BYTES); - os.flush(); - os.close(); - - cm.rename(srcFilePath, destFilePath); - assertTrue(cm.fileExists(destFilePath)); - assertFalse(cm.fileExists(srcFilePath)); - } - - @Test - public void testFileRenameDirNotExists() throws Exception { - File srcDir = new File(rootDir, "src"); - srcDir.mkdir(); - - String srcFilePath = "src/" + runtime.getMethodName(); - String destFilePath = "dest/" + runtime.getMethodName(); - OutputStream os = cm.openOutputStream(srcFilePath); - os.write(TEST_BYTES); - os.flush(); - os.close(); - - try { - cm.rename(srcFilePath, destFilePath); - fail("Should fail to rename if the dest dir doesn't exist"); - } catch (NoSuchFileException e) { - // expected - } - assertFalse(cm.fileExists(destFilePath)); - assertTrue(cm.fileExists(srcFilePath)); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClock.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClock.java deleted file mode 100644 index e49459a8fb8..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClock.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.testing.executors; - -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; - -/** - * A mock implementation of {@link Clock}. - */ -public class MockClock extends Clock { - - private final ZoneId zoneId; - private Instant now = Instant.ofEpochMilli(0); - - public MockClock() { - this(ZoneId.systemDefault()); - } - - private MockClock(ZoneId zoneId) { - this.zoneId = zoneId; - } - - @Override - public ZoneId getZone() { - return zoneId; - } - - @Override - public MockClock withZone(ZoneId zone) { - return new MockClock(zone); - } - - @Override - public Instant instant() { - return now; - } - - /** - * Advance the clock by the given amount of time. - * - * @param duration duration to advance. - */ - public void advance(Duration duration) { - now = now.plus(duration); - } -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClockTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClockTest.java deleted file mode 100644 index 9eaaf6256e3..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockClockTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.testing.executors; - -import static org.junit.Assert.assertEquals; - -import java.time.Duration; -import org.junit.Before; -import org.junit.Test; - -/** - * Test {@link MockClock}. - */ -public class MockClockTest { - - private MockClock clock; - - @Before - public void setup() { - this.clock = new MockClock(); - } - - @Test - public void testAdvance() { - assertEquals(0L, clock.millis()); - clock.advance(Duration.ofMillis(10)); - assertEquals(10L, clock.millis()); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorController.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorController.java deleted file mode 100644 index 01489227205..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorController.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.testing.executors; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doAnswer; - -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.SettableFuture; -import java.time.Duration; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import lombok.Data; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.junit.Assert; -import org.mockito.stubbing.Answer; - -/** - * A mocked scheduled executor that records scheduled tasks and executes them when the clock is - * advanced past their execution time. - */ -@Slf4j -public class MockExecutorController { - public static final String THREAD_NAME_PREFIX = "realWriteExecutor-"; - - @Data - @Getter - private class DeferredTask implements ScheduledFuture, Runnable { - - private final Runnable runnable; - private final long scheduledAtMillis; - @Getter - private final CompletableFuture future; - - public DeferredTask(Runnable runnable, - long delayTimeMs) { - this.runnable = runnable; - this.scheduledAtMillis = delayTimeMs + clock.millis(); - this.future = FutureUtils.createFuture(); - } - - @Override - public long getDelay(TimeUnit unit) { - return unit.convert(scheduledAtMillis - clock.millis(), TimeUnit.MILLISECONDS); - } - - @Override - public int compareTo(Delayed o) { - return Long.compare(getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS)); - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return future.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return future.isCancelled(); - } - - @Override - public boolean isDone() { - return future.isDone(); - } - - @Override - public Void get() throws InterruptedException, ExecutionException { - future.get(); - return null; - } - - @Override - public Void get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - future.get(timeout, unit); - return null; - } - - @Override - public void run() { - runnable.run(); - FutureUtils.complete(future, null); - } - - } - - @Getter - private final MockClock clock = new MockClock(); - private final List deferredTasks = Lists.newArrayList(); - private final ExecutorService executor; - - public MockExecutorController(ExecutorService executor) { - this.executor = executor; - } - - private void runTask(Runnable runnable) { - try { - if (null == executor) { - runnable.run(); - } else { - Assert.assertThat("calling this on the same thread will result in deadlock", - Thread.currentThread().getName(), - not(containsString(THREAD_NAME_PREFIX))); - executor.submit(runnable).get(); - } - } catch (AssertionError ae) { - throw ae; - } catch (Throwable t) { - log.error("Got unexpected exception while submitting a Runnable", t); - fail("Got unexpected exception while submitting a Runnable " + t.getMessage()); - } - } - - private Future runTaskAsync(Runnable runnable) { - if (null == executor) { - runnable.run(); - return CompletableFuture.completedFuture(null); - } else { - return executor.submit(runnable); - } - } - - public MockExecutorController controlSubmit(ScheduledExecutorService service) { - doAnswer(answerNow(this)).when(service).submit(any(Runnable.class)); - return this; - } - - public MockExecutorController controlExecute(ScheduledExecutorService service) { - doAnswer(answerNowAsync(this)).when(service).execute(any(Runnable.class)); - return this; - } - - public MockExecutorController controlSchedule(ScheduledExecutorService service) { - doAnswer(answerDelay(this)).when(service).schedule(any(Runnable.class), anyLong(), any(TimeUnit.class)); - return this; - } - - public MockExecutorController controlScheduleAtFixedRate(ScheduledExecutorService service, - int maxInvocations) { - doAnswer(answerAtFixedRate(this, maxInvocations)) - .when(service) - .scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class)); - return this; - } - - private static Answer> answerAtFixedRate(MockExecutorController controller, int numTimes) { - return invocationOnMock -> { - Runnable task = invocationOnMock.getArgument(0); - long initialDelay = invocationOnMock.getArgument(1); - long delay = invocationOnMock.getArgument(2); - TimeUnit unit = invocationOnMock.getArgument(3); - - DeferredTask deferredTask = null; - for (int i = 0; i < numTimes; i++) { - long delayMs = unit.toMillis(initialDelay) + i * unit.toMillis(delay); - - deferredTask = controller.addDelayedTask( - controller, - delayMs, - task); - } - return deferredTask; - }; - } - - private static Answer> answerDelay(MockExecutorController executor) { - return invocationOnMock -> { - - Runnable task = invocationOnMock.getArgument(0); - long value = invocationOnMock.getArgument(1); - TimeUnit unit = invocationOnMock.getArgument(2); - DeferredTask deferredTask = executor.addDelayedTask(executor, unit.toMillis(value), task); - if (value <= 0) { - executor.runTask(task); - FutureUtils.complete(deferredTask.future, null); - } - return deferredTask; - }; - } - - private static Answer> answerNowAsync(MockExecutorController controller) { - return invocationOnMock -> { - Runnable task = invocationOnMock.getArgument(0); - return controller.runTaskAsync(task); - }; - } - - private static Answer> answerNow(MockExecutorController controller) { - return invocationOnMock -> { - - Runnable task = invocationOnMock.getArgument(0); - controller.runTask(task); - SettableFuture future = SettableFuture.create(); - future.set(null); - return future; - }; - } - - private DeferredTask addDelayedTask( - MockExecutorController executor, - long delayTimeMs, - Runnable task) { - checkArgument(delayTimeMs >= 0); - DeferredTask deferredTask = new DeferredTask(task, delayTimeMs); - executor.deferredTasks.add(deferredTask); - return deferredTask; - } - - public void advance(Duration duration) { - clock.advance(duration); - Iterator entries = deferredTasks.iterator(); - List toExecute = Lists.newArrayList(); - while (entries.hasNext()) { - DeferredTask next = entries.next(); - if (next.getDelay(TimeUnit.MILLISECONDS) <= 0) { - entries.remove(); - toExecute.add(next); - } - } - for (DeferredTask task : toExecute) { - runTask(task); - } - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerTest.java deleted file mode 100644 index 62f31e5fdef..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.testing.executors; - -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.time.Duration; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.junit.Before; -import org.junit.Test; - -/** - * Test {@link MockExecutorController}. - */ -public class MockExecutorControllerTest { - - private static final int MAX_SCHEDULES = 5; - - private ScheduledExecutorService executor; - private MockExecutorController mockExecutorControl; - - @Before - public void setup() { - this.executor = mock(ScheduledExecutorService.class); - this.mockExecutorControl = new MockExecutorController(null) - .controlExecute(executor) - .controlSubmit(executor) - .controlSchedule(executor) - .controlScheduleAtFixedRate(executor, MAX_SCHEDULES); - } - - @Test - public void testSubmit() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.submit(task); - verify(task, times(1)).run(); - } - - @Test - public void testExecute() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.execute(task); - verify(task, times(1)).run(); - } - - @Test - public void testDelay() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.schedule(task, 10, TimeUnit.MILLISECONDS); - mockExecutorControl.advance(Duration.ofMillis(5)); - verify(task, times(0)).run(); - mockExecutorControl.advance(Duration.ofMillis(10)); - verify(task, times(1)).run(); - } - - @Test - public void testScheduleAtFixedRate() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - executor.scheduleAtFixedRate(task, 5, 10, TimeUnit.MILLISECONDS); - - // first delay - mockExecutorControl.advance(Duration.ofMillis(2)); - verify(task, times(0)).run(); - mockExecutorControl.advance(Duration.ofMillis(3)); - verify(task, times(1)).run(); - - // subsequent delays - for (int i = 1; i < MAX_SCHEDULES; i++) { - mockExecutorControl.advance(Duration.ofMillis(2)); - verify(task, times(i)).run(); - mockExecutorControl.advance(Duration.ofMillis(8)); - verify(task, times(i + 1)).run(); - } - - // no more invocations - mockExecutorControl.advance(Duration.ofMillis(500)); - verify(task, times(MAX_SCHEDULES)).run(); - } - -} diff --git a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerWithSchedulerTest.java b/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerWithSchedulerTest.java deleted file mode 100644 index 2e860c7e6ab..00000000000 --- a/stream/statelib/src/test/java/org/apache/bookkeeper/statelib/testing/executors/MockExecutorControllerWithSchedulerTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.statelib.testing.executors; - -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.time.Duration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Test {@link MockExecutorController}. - */ -public class MockExecutorControllerWithSchedulerTest { - - private static final int MAX_SCHEDULES = 5; - - private ScheduledExecutorService mockExecutor; - private ScheduledExecutorService executor; - private MockExecutorController mockExecutorControl; - - @Before - public void setup() { - this.executor = Executors.newSingleThreadScheduledExecutor(); - this.mockExecutor = mock(ScheduledExecutorService.class); - this.mockExecutorControl = new MockExecutorController(executor) - .controlExecute(mockExecutor) - .controlSubmit(mockExecutor) - .controlSchedule(mockExecutor) - .controlScheduleAtFixedRate(mockExecutor, MAX_SCHEDULES); - } - - @After - public void teardown() { - if (null != executor) { - executor.shutdown(); - } - } - - @Test - public void testSubmit() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - mockExecutor.submit(task); - verify(task, times(1)).run(); - } - - @Test - public void testExecute() throws ExecutionException, InterruptedException, TimeoutException { - final CompletableFuture future = new CompletableFuture<>(); - Runnable task = mock(Runnable.class); - doAnswer(x -> future.complete(null)).when(task).run(); - mockExecutor.execute(task); - future.get(5000, TimeUnit.MILLISECONDS); - verify(task, times(1)).run(); - } - - @Test - public void testDelay() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - mockExecutor.schedule(task, 10, TimeUnit.MILLISECONDS); - mockExecutorControl.advance(Duration.ofMillis(5)); - verify(task, times(0)).run(); - mockExecutorControl.advance(Duration.ofMillis(10)); - verify(task, times(1)).run(); - } - - @Test - public void testScheduleAtFixedRate() { - Runnable task = mock(Runnable.class); - doNothing().when(task).run(); - mockExecutor.scheduleAtFixedRate(task, 5, 10, TimeUnit.MILLISECONDS); - - // first delay - mockExecutorControl.advance(Duration.ofMillis(2)); - verify(task, times(0)).run(); - mockExecutorControl.advance(Duration.ofMillis(3)); - verify(task, times(1)).run(); - - // subsequent delays - for (int i = 1; i < MAX_SCHEDULES; i++) { - mockExecutorControl.advance(Duration.ofMillis(2)); - verify(task, times(i)).run(); - mockExecutorControl.advance(Duration.ofMillis(8)); - verify(task, times(i + 1)).run(); - } - - // no more invocations - mockExecutorControl.advance(Duration.ofMillis(500)); - verify(task, times(MAX_SCHEDULES)).run(); - } - -} diff --git a/stream/storage/api/src/test/java/org/apache/bookkeeper/stream/storage/conf/TestStorageConfiguration.java b/stream/storage/api/src/test/java/org/apache/bookkeeper/stream/storage/conf/TestStorageConfiguration.java deleted file mode 100644 index a5d23160488..00000000000 --- a/stream/storage/api/src/test/java/org/apache/bookkeeper/stream/storage/conf/TestStorageConfiguration.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed 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. - */ -package org.apache.bookkeeper.stream.storage.conf; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.junit.Test; - -/** - * Unit tests for {@link StorageConfiguration}. - */ -public class TestStorageConfiguration { - - @Test(timeout = 60000) - public void testGetStorageSettings() { - CompositeConfiguration conf = new CompositeConfiguration(); - conf.setProperty("xxx.key", "xxx.value"); - conf.setProperty("storage.key", "storage.value"); - conf.setProperty("storage-key", "storage-value"); - - StorageConfiguration storageConf = new StorageConfiguration(conf); - assertEquals("storage.value", storageConf.getString("key")); - assertTrue(storageConf.containsKey("key")); - assertFalse(storageConf.containsKey("xxx.key")); - assertFalse(storageConf.containsKey("storage.key")); - assertFalse(storageConf.containsKey("storage-key")); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestStorageContainerStoreBuilder.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestStorageContainerStoreBuilder.java deleted file mode 100644 index 59d6a1306bc..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestStorageContainerStoreBuilder.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.stream.storage; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import java.net.URI; -import org.apache.bookkeeper.clients.impl.internal.api.StorageServerClientManager; -import org.apache.bookkeeper.stream.storage.api.StorageContainerStore; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerManagerFactory; -import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration; -import org.apache.bookkeeper.stream.storage.impl.StorageContainerStoreImpl; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link StorageContainerStoreBuilder}. - */ -public class TestStorageContainerStoreBuilder { - - private MVCCStoreFactory storeFactory; - private final URI uri = URI.create("distributedlog://127.0.0.1/stream/storage"); - - @Before - public void setup() { - this.storeFactory = mock(MVCCStoreFactory.class); - } - - @Test(expected = NullPointerException.class) - public void testBuildNullConfiguration() { - StorageContainerStoreBuilder.newBuilder() - .withStorageConfiguration(null) - .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class)) - .withStorageResources(StorageResources.create()) - .withRangeStoreFactory(storeFactory) - .withDefaultBackendUri(uri) - .withStorageServerClientManager(() -> mock(StorageServerClientManager.class)) - .build(); - } - - @Test(expected = NullPointerException.class) - public void testBuildNullResources() { - StorageContainerStoreBuilder.newBuilder() - .withStorageConfiguration(mock(StorageConfiguration.class)) - .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class)) - .withStorageResources(null) - .withRangeStoreFactory(storeFactory) - .withStorageServerClientManager(() -> mock(StorageServerClientManager.class)) - .withDefaultBackendUri(uri) - .build(); - } - - @Test(expected = NullPointerException.class) - public void testBuildNullRGManagerFactory() { - StorageContainerStoreBuilder.newBuilder() - .withStorageConfiguration(mock(StorageConfiguration.class)) - .withStorageContainerManagerFactory(null) - .withStorageResources(StorageResources.create()) - .withRangeStoreFactory(storeFactory) - .withStorageServerClientManager(() -> mock(StorageServerClientManager.class)) - .withDefaultBackendUri(uri) - .build(); - } - - @Test(expected = NullPointerException.class) - public void testBuildNullStoreFactory() { - StorageContainerStoreBuilder.newBuilder() - .withStorageConfiguration(mock(StorageConfiguration.class)) - .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class)) - .withStorageResources(StorageResources.create()) - .withRangeStoreFactory(null) - .withStorageServerClientManager(() -> mock(StorageServerClientManager.class)) - .withDefaultBackendUri(uri) - .build(); - } - - @Test(expected = NullPointerException.class) - public void testBuildNullDefaultBackendUri() { - StorageContainerStoreBuilder.newBuilder() - .withStorageConfiguration(mock(StorageConfiguration.class)) - .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class)) - .withStorageResources(StorageResources.create()) - .withRangeStoreFactory(storeFactory) - .withStorageServerClientManager(() -> mock(StorageServerClientManager.class)) - .withDefaultBackendUri(null) - .build(); - } - - @Test(expected = NullPointerException.class) - public void testBuildStorageServerClientManager() { - StorageContainerStoreBuilder.newBuilder() - .withStorageConfiguration(mock(StorageConfiguration.class)) - .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class)) - .withStorageResources(StorageResources.create()) - .withRangeStoreFactory(storeFactory) - .withStorageServerClientManager(null) - .withDefaultBackendUri(uri) - .build(); - } - - @Test - public void testBuild() { - StorageContainerStore storageContainerStore = StorageContainerStoreBuilder.newBuilder() - .withStorageConfiguration(mock(StorageConfiguration.class)) - .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class)) - .withStorageResources(StorageResources.create()) - .withRangeStoreFactory(storeFactory) - .withStorageServerClientManager(() -> mock(StorageServerClientManager.class)) - .withDefaultBackendUri(uri) - .build(); - assertTrue(storageContainerStore instanceof StorageContainerStoreImpl); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java deleted file mode 100644 index 5381a72805a..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.stream.storage.impl; - -import static org.apache.bookkeeper.common.util.ListenableFutures.fromListenableFuture; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateStreamRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteStreamRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetActiveRangesRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetStreamRequest; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.protobuf.ByteString; -import io.grpc.Channel; -import io.grpc.ClientInterceptors; -import io.grpc.ManagedChannel; -import io.grpc.Server; -import io.grpc.ServerServiceDefinition; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import java.util.Collection; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ThreadLocalRandom; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.clients.impl.container.StorageContainerClientInterceptor; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.grpc.proxy.ProxyHandlerRegistry; -import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.StreamName; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceFutureStub; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc; -import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRangeServiceFutureStub; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceFutureStub; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.storage.StorageResources; -import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService; -import org.apache.bookkeeper.stream.storage.api.service.RangeStoreServiceFactory; -import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration; -import org.apache.bookkeeper.stream.storage.impl.grpc.GrpcServices; -import org.apache.bookkeeper.stream.storage.impl.sc.LocalStorageContainerManager; -import org.apache.bookkeeper.stream.storage.impl.service.RangeStoreContainerServiceFactoryImpl; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory; -import org.apache.commons.configuration.CompositeConfiguration; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link StorageContainerStoreImpl}. - */ -@Slf4j -public class TestStorageContainerStoreImpl { - - private static final StreamProperties streamProps = StreamProperties.newBuilder() - .setStorageContainerId(System.currentTimeMillis()) - .setStreamId(System.currentTimeMillis()) - .setStreamName("test-create-add-stream-request") - .setStreamConf(DEFAULT_STREAM_CONF) - .build(); - - private static StreamName createStreamName(String name) { - return StreamName.newBuilder() - .setNamespaceName(name + "_col") - .setStreamName(name + "_stream") - .build(); - } - - private static Endpoint createEndpoint(String hostname, - int port) { - return Endpoint.newBuilder() - .setHostname(hostname) - .setPort(port) - .build(); - } - - private final CompositeConfiguration compConf = - new CompositeConfiguration(); - private final StorageConfiguration storageConf = - new StorageConfiguration(compConf); - private final NamespaceConfiguration namespaceConf = - NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - private final StorageResources resources = StorageResources.create(); - private RangeStoreService mockRangeStoreService; - private StorageContainerStoreImpl rangeStore; - private Server server; - private Channel channel; - private TableServiceFutureStub tableService; - private RootRangeServiceFutureStub rootRangeService; - private MetaRangeServiceFutureStub metaRangeService; - private long scId; - - // - // Utils for table api - // - private static final ByteString TEST_ROUTING_KEY = ByteString.copyFromUtf8("test-routing-key"); - private static final ByteString TEST_KEY = ByteString.copyFromUtf8("test-key"); - private static final ByteString TEST_VAL = ByteString.copyFromUtf8("test-val"); - private static final RoutingHeader TEST_ROUTING_HEADER = RoutingHeader.newBuilder() - .setRKey(TEST_ROUTING_KEY) - .setStreamId(1234L) - .setRangeId(1256L) - .build(); - private static final ResponseHeader TEST_RESP_HEADER = ResponseHeader.newBuilder() - .setRoutingHeader(TEST_ROUTING_HEADER) - .build(); - - private static PutRequest createPutRequest() { - return PutRequest.newBuilder() - .setHeader(TEST_ROUTING_HEADER) - .setKey(TEST_KEY) - .setValue(TEST_VAL) - .build(); - } - - private static PutResponse createPutResponse(StatusCode code) { - return PutResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder(TEST_RESP_HEADER) - .setCode(code) - .build()) - .build(); - } - - private static RangeRequest createRangeRequest() { - return RangeRequest.newBuilder() - .setHeader(TEST_ROUTING_HEADER) - .setKey(TEST_KEY) - .build(); - } - - private static RangeResponse createRangeResponse(StatusCode code) { - return RangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder(TEST_RESP_HEADER) - .setCode(code) - .build()) - .setCount(0) - .build(); - } - - private static DeleteRangeRequest createDeleteRequest() { - return DeleteRangeRequest.newBuilder() - .setHeader(TEST_ROUTING_HEADER) - .setKey(TEST_KEY) - .build(); - } - - private static DeleteRangeResponse createDeleteResponse(StatusCode code) { - return DeleteRangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder(TEST_RESP_HEADER) - .setCode(code) - .build()) - .setDeleted(0) - .build(); - } - - @SuppressWarnings("unchecked") - @Before - public void setUp() throws Exception { - Endpoint endpoint = createEndpoint("127.0.0.1", 0); - - // create the client manager - MVCCStoreFactory storeFactory = mock(MVCCStoreFactory.class); - MVCCAsyncStore store = mock(MVCCAsyncStore.class); - when(storeFactory.openStore(anyLong(), anyLong(), anyLong(), anyInt())) - .thenReturn(FutureUtils.value(store)); - when(storeFactory.closeStores(anyLong())) - .thenReturn(FutureUtils.Void()); - - RangeStoreServiceFactory rangeStoreServiceFactory = mock(RangeStoreServiceFactory.class); - mockRangeStoreService = mock(RangeStoreService.class); - when(mockRangeStoreService.start()).thenReturn(FutureUtils.Void()); - when(mockRangeStoreService.stop()).thenReturn(FutureUtils.Void()); - when(rangeStoreServiceFactory.createService(anyLong())) - .thenReturn(mockRangeStoreService); - - rangeStore = new StorageContainerStoreImpl( - storageConf, - (storeConf, rgRegistry) - -> new LocalStorageContainerManager(endpoint, storeConf, rgRegistry, 2), - new RangeStoreContainerServiceFactoryImpl(rangeStoreServiceFactory), - null, - NullStatsLogger.INSTANCE); - - rangeStore.start(); - - final String serverName = "test-server"; - - Collection grpcServices = GrpcServices.create(null); - ProxyHandlerRegistry.Builder registryBuilder = ProxyHandlerRegistry.newBuilder(); - grpcServices.forEach(service -> registryBuilder.addService(service)); - ProxyHandlerRegistry registry = registryBuilder - .setChannelFinder(rangeStore) - .build(); - server = InProcessServerBuilder.forName(serverName) - .fallbackHandlerRegistry(registry) - .directExecutor() - .build() - .start(); - - channel = InProcessChannelBuilder.forName(serverName) - .usePlaintext() - .build(); - - scId = ThreadLocalRandom.current().nextInt(2); - - // intercept the channel with storage container information. - channel = ClientInterceptors.intercept( - channel, - new StorageContainerClientInterceptor(scId)); - - - tableService = TableServiceGrpc.newFutureStub(channel); - metaRangeService = MetaRangeServiceGrpc.newFutureStub(channel); - rootRangeService = RootRangeServiceGrpc.newFutureStub(channel); - } - - @After - public void tearDown() { - if (null != channel) { - if (channel instanceof ManagedChannel) { - ((ManagedChannel) channel).shutdown(); - } - } - if (null != server) { - server.shutdown(); - } - if (null != rangeStore) { - rangeStore.close(); - } - } - - private void verifyNotFoundException(CompletableFuture future, - Status status) - throws InterruptedException { - try { - future.get(); - } catch (ExecutionException ee) { - assertTrue(ee.getCause() instanceof StatusRuntimeException); - StatusRuntimeException sre = (StatusRuntimeException) ee.getCause(); - assertEquals(status, sre.getStatus()); - } - } - - // - // Namespace API - // - - @Test - public void testCreateNamespaceNoRootStorageContainerStore() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - String colName = "test-create-namespace-no-root-storage-container-store"; - verifyNotFoundException(fromListenableFuture( - rootRangeService.createNamespace(createCreateNamespaceRequest(colName, namespaceConf))), - Status.NOT_FOUND); - } - - @Test - public void testDeleteNamespaceNoRootStorageContainerStore() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - String colName = "test-delete-namespace-no-root-storage-container-store"; - verifyNotFoundException(fromListenableFuture( - rootRangeService.deleteNamespace(createDeleteNamespaceRequest(colName))), - Status.NOT_FOUND); - } - - @Test - public void testGetNamespaceNoRootStorageContainerStore() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - String colName = "test-get-namespace-no-root-storage-container-store"; - verifyNotFoundException(fromListenableFuture( - rootRangeService.getNamespace(createGetNamespaceRequest(colName))), - Status.NOT_FOUND); - } - - @Test - public void testCreateNamespaceMockRootStorageContainerStore() throws Exception { - String colName = "test-create-namespace-mock-root-storage-container-store"; - - CreateNamespaceResponse createResp = CreateNamespaceResponse.newBuilder() - .setCode(StatusCode.NAMESPACE_EXISTS) - .build(); - CreateNamespaceRequest request = createCreateNamespaceRequest(colName, namespaceConf); - - when(mockRangeStoreService.createNamespace(request)) - .thenReturn(CompletableFuture.completedFuture(createResp)); - - CompletableFuture createRespFuture = - fromListenableFuture(rootRangeService.createNamespace(request)); - assertTrue(createResp == createRespFuture.get()); - verify(mockRangeStoreService, times(1)).createNamespace(request); - } - - @Test - public void testDeleteNamespaceMockRootStorageContainerStore() throws Exception { - String colName = "test-delete-namespace-no-root-storage-container-store"; - - DeleteNamespaceResponse deleteResp = DeleteNamespaceResponse.newBuilder() - .setCode(StatusCode.NAMESPACE_NOT_FOUND) - .build(); - DeleteNamespaceRequest request = createDeleteNamespaceRequest(colName); - - when(mockRangeStoreService.deleteNamespace(request)) - .thenReturn(CompletableFuture.completedFuture(deleteResp)); - - CompletableFuture deleteRespFuture = - fromListenableFuture(rootRangeService.deleteNamespace(request)); - verify(mockRangeStoreService, times(1)).deleteNamespace(request); - assertTrue(deleteResp == deleteRespFuture.get()); - } - - @Test - public void testGetNamespaceMockRootStorageContainerStore() throws Exception { - String colName = "test-get-namespace-no-root-storage-container-store"; - - GetNamespaceResponse getResp = GetNamespaceResponse.newBuilder() - .setCode(StatusCode.NAMESPACE_NOT_FOUND) - .build(); - GetNamespaceRequest request = createGetNamespaceRequest(colName); - - when(mockRangeStoreService.getNamespace(request)).thenReturn( - CompletableFuture.completedFuture(getResp)); - - CompletableFuture getRespFuture = - fromListenableFuture(rootRangeService.getNamespace(request)); - verify(mockRangeStoreService, times(1)).getNamespace(request); - assertTrue(getResp == getRespFuture.get()); - } - - // - // Test Stream API - // - - @Test - public void testCreateStreamNoRootStorageContainerStore() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - String colName = "test-create-namespace-no-root-storage-container-store"; - String streamName = colName; - verifyNotFoundException(fromListenableFuture( - rootRangeService.createStream(createCreateStreamRequest(colName, streamName, DEFAULT_STREAM_CONF))), - Status.NOT_FOUND); - } - - @Test - public void testDeleteStreamNoRootStorageContainerStore() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - String colName = "test-delete-namespace-no-root-storage-container-store"; - String streamName = colName; - verifyNotFoundException(fromListenableFuture( - rootRangeService.deleteStream(createDeleteStreamRequest(colName, streamName))), - Status.NOT_FOUND); - } - - @Test - public void testGetStreamNoRootStorageContainerStore() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - String colName = "test-get-namespace-no-root-storage-container-store"; - String streamName = colName; - verifyNotFoundException(fromListenableFuture( - rootRangeService.getStream(createGetStreamRequest(colName, streamName))), - Status.NOT_FOUND); - } - - @Test - public void testCreateStreamMockRootStorageContainerStore() throws Exception { - String colName = "test-create-namespace-mock-root-storage-container-store"; - String streamName = colName; - - CreateStreamResponse createResp = CreateStreamResponse.newBuilder() - .setCode(StatusCode.STREAM_EXISTS) - .build(); - CreateStreamRequest createReq = createCreateStreamRequest(colName, streamName, DEFAULT_STREAM_CONF); - when(mockRangeStoreService.createStream(createReq)).thenReturn( - CompletableFuture.completedFuture(createResp)); - - CompletableFuture createRespFuture = - fromListenableFuture(rootRangeService.createStream(createReq)); - verify(mockRangeStoreService, times(1)).createStream(createReq); - assertTrue(createResp == createRespFuture.get()); - } - - @Test - public void testDeleteStreamMockRootStorageContainerStore() throws Exception { - String colName = "test-delete-namespace-no-root-storage-container-store"; - String streamName = colName; - - DeleteStreamResponse deleteResp = DeleteStreamResponse.newBuilder() - .setCode(StatusCode.STREAM_NOT_FOUND) - .build(); - DeleteStreamRequest deleteReq = createDeleteStreamRequest(colName, streamName); - when(mockRangeStoreService.deleteStream(deleteReq)).thenReturn( - CompletableFuture.completedFuture(deleteResp)); - - CompletableFuture deleteRespFuture = - fromListenableFuture(rootRangeService.deleteStream(deleteReq)); - verify(mockRangeStoreService, times(1)).deleteStream(deleteReq); - assertTrue(deleteResp == deleteRespFuture.get()); - } - - @Test - public void testGetStreamMockRootStorageContainerStore() throws Exception { - String colName = "test-get-namespace-no-root-storage-container-store"; - String streamName = colName; - - GetStreamResponse getResp = GetStreamResponse.newBuilder() - .setCode(StatusCode.STREAM_NOT_FOUND) - .build(); - GetStreamRequest getReq = createGetStreamRequest(colName, streamName); - when(mockRangeStoreService.getStream(getReq)).thenReturn( - CompletableFuture.completedFuture(getResp)); - - CompletableFuture getRespFuture = - fromListenableFuture(rootRangeService.getStream(getReq)); - verify(mockRangeStoreService, times(1)).getStream(getReq); - assertTrue(getResp == getRespFuture.get()); - } - - @Test - public void testGetActiveRangesNoManager() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - verifyNotFoundException(fromListenableFuture( - metaRangeService.getActiveRanges(createGetActiveRangesRequest(34L))), - Status.NOT_FOUND); - } - - @Test - public void testGetActiveRangesMockManager() throws Exception { - GetActiveRangesResponse resp = GetActiveRangesResponse.newBuilder() - .setCode(StatusCode.STREAM_NOT_FOUND) - .build(); - GetActiveRangesRequest request = createGetActiveRangesRequest(34L); - - when(mockRangeStoreService.getActiveRanges(request)) - .thenReturn(CompletableFuture.completedFuture(resp)); - - CompletableFuture future = fromListenableFuture( - metaRangeService.getActiveRanges(request)); - verify(mockRangeStoreService, times(1)).getActiveRanges(request); - assertTrue(resp == future.get()); - } - - - // - // Table API - // - - @Test - public void testPutNoStorageContainer() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - verifyNotFoundException(fromListenableFuture( - tableService.put(createPutRequest())), - Status.NOT_FOUND); - } - - @Test - public void testDeleteNoStorageContainer() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - verifyNotFoundException(fromListenableFuture( - tableService.delete(createDeleteRequest())), - Status.NOT_FOUND); - } - - @Test - public void testRangeNoStorageContainer() throws Exception { - rangeStore.getRegistry().stopStorageContainer(scId).join(); - - verifyNotFoundException(fromListenableFuture( - tableService.range(createRangeRequest())), - Status.NOT_FOUND); - } - - @Test - public void testRangeMockStorageContainer() throws Exception { - RangeResponse response = createRangeResponse(StatusCode.SUCCESS); - RangeRequest request = createRangeRequest(); - - when(mockRangeStoreService.range(request)) - .thenReturn(CompletableFuture.completedFuture(response)); - - CompletableFuture future = fromListenableFuture( - tableService.range(request)); - verify(mockRangeStoreService, times(1)).range(eq(request)); - assertTrue(response == future.get()); - } - - @Test - public void testDeleteMockStorageContainer() throws Exception { - DeleteRangeResponse response = createDeleteResponse(StatusCode.SUCCESS); - DeleteRangeRequest request = createDeleteRequest(); - - when(mockRangeStoreService.delete(request)) - .thenReturn(CompletableFuture.completedFuture(response)); - - CompletableFuture future = fromListenableFuture( - tableService.delete(request)); - verify(mockRangeStoreService, times(1)).delete(eq(request)); - assertTrue(response == future.get()); - } - - @Test - public void testPutMockStorageContainer() throws Exception { - PutResponse response = createPutResponse(StatusCode.SUCCESS); - PutRequest request = createPutRequest(); - - when(mockRangeStoreService.put(request)) - .thenReturn(CompletableFuture.completedFuture(response)); - - CompletableFuture future = fromListenableFuture( - tableService.put(request)); - verify(mockRangeStoreService, times(1)).put(eq(request)); - assertTrue(response == future.get()); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerImplTest.java deleted file mode 100644 index 63967a68309..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerImplTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.cluster; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.apache.bookkeeper.discover.RegistrationClient; -import org.apache.bookkeeper.stream.storage.api.cluster.ClusterController; -import org.apache.bookkeeper.stream.storage.api.cluster.ClusterControllerLeader; -import org.apache.bookkeeper.stream.storage.api.cluster.ClusterControllerLeaderSelector; -import org.apache.bookkeeper.stream.storage.api.cluster.ClusterMetadataStore; -import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration; -import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerController; -import org.apache.commons.configuration.CompositeConfiguration; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link ClusterControllerImpl}. - */ -public class ClusterControllerImplTest { - - private ClusterControllerLeaderSelector leaderSelector; - - private ClusterController service; - - @Before - public void setup() { - this.leaderSelector = mock(ClusterControllerLeaderSelector.class); - this.service = new ClusterControllerImpl( - mock(ClusterMetadataStore.class), - mock(RegistrationClient.class), - mock(StorageContainerController.class), - leaderSelector, - new StorageConfiguration(new CompositeConfiguration())); - } - - @Test - public void testInitialize() { - verify(leaderSelector, times(1)) - .initialize(any(ClusterControllerLeader.class)); - } - - @Test - public void testStart() { - service.start(); - verify(leaderSelector, times(1)).start(); - } - - @Test - public void testStop() { - service.start(); - service.stop(); - verify(leaderSelector, times(1)).close(); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerLeaderImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerLeaderImplTest.java deleted file mode 100644 index 6ed0c432dbf..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ClusterControllerLeaderImplTest.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.cluster; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import java.time.Duration; -import java.util.Collections; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.discover.RegistrationClient; -import org.apache.bookkeeper.discover.RegistrationClient.RegistrationListener; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stream.proto.cluster.ClusterAssignmentData; -import org.apache.bookkeeper.stream.proto.cluster.ClusterMetadata; -import org.apache.bookkeeper.stream.storage.api.cluster.ClusterMetadataStore; -import org.apache.bookkeeper.stream.storage.impl.sc.DefaultStorageContainerController; -import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerController; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.internal.util.collections.Sets; - -/** - * Unit test {@link ClusterControllerLeaderImpl}. - */ -@Slf4j -public class ClusterControllerLeaderImplTest { - - private static final int NUM_STORAGE_CONTAINERS = 32; - - private ClusterMetadataStore metadataStore; - private ClusterControllerLeaderImpl clusterController; - private ExecutorService leaderExecutor; - - private final Semaphore coordSem = new Semaphore(0); - private final AtomicReference regListenerRef = - new AtomicReference<>(null); - private final CompletableFuture watchFuture = new CompletableFuture<>(); - - @Before - public void setup() { - this.metadataStore = spy(new InMemClusterMetadataStore(NUM_STORAGE_CONTAINERS)); - this.metadataStore.initializeCluster(NUM_STORAGE_CONTAINERS); - // wrap the metadata store with the coord sem with coordinating testing - ClusterMetadataStore originalStore = metadataStore; - this.metadataStore = new ClusterMetadataStore() { - @Override - public boolean initializeCluster(int numStorageContainers, Optional segmentStorePath) { - return originalStore.initializeCluster(numStorageContainers); - } - - @Override - public ClusterAssignmentData getClusterAssignmentData() { - return originalStore.getClusterAssignmentData(); - } - - @Override - public void updateClusterAssignmentData(ClusterAssignmentData assignmentData) { - originalStore.updateClusterAssignmentData(assignmentData); - - // notify when cluster assignment data is updated. - coordSem.release(); - } - - @Override - public void watchClusterAssignmentData(Consumer watcher, Executor executor) { - originalStore.watchClusterAssignmentData(watcher, executor); - } - - @Override - public void unwatchClusterAssignmentData(Consumer watcher) { - originalStore.unwatchClusterAssignmentData(watcher); - } - - @Override - public ClusterMetadata getClusterMetadata() { - return originalStore.getClusterMetadata(); - } - - @Override - public void updateClusterMetadata(ClusterMetadata clusterMetadata) { - originalStore.updateClusterMetadata(clusterMetadata); - } - - @Override - public void close() { - originalStore.close(); - } - }; - - StorageContainerController scController = spy(new DefaultStorageContainerController()); - RegistrationClient mockRegClient = mock(RegistrationClient.class); - when(mockRegClient.watchWritableBookies(any(RegistrationListener.class))) - .thenAnswer(invocationOnMock -> { - RegistrationListener listener = invocationOnMock.getArgument(0); - regListenerRef.set(listener); - return watchFuture; - }); - doAnswer(invocationOnMock -> { - RegistrationListener listener = invocationOnMock.getArgument(0); - regListenerRef.compareAndSet(listener, null); - return null; - }).when(mockRegClient).unwatchWritableBookies(any(RegistrationListener.class)); - - this.clusterController = new ClusterControllerLeaderImpl( - metadataStore, - scController, - mockRegClient, - Duration.ofMillis(10)); - this.leaderExecutor = Executors.newSingleThreadExecutor(); - } - - @After - public void teardown() { - if (null != metadataStore) { - metadataStore.close(); - } - if (null != leaderExecutor) { - leaderExecutor.shutdown(); - } - } - - @Test - public void testProcessAsLeader() throws Exception { - clusterController.suspend(); - assertTrue(clusterController.isSuspended()); - - // start the leader controller - leaderExecutor.submit(() -> { - try { - clusterController.processAsLeader(); - } catch (Exception e) { - log.info("Encountered exception when cluster controller processes as a leader", e); - } - }); - - // resume the controller - clusterController.resume(); - assertFalse(clusterController.isSuspended()); - - // simulate `watchWritableBookies` is done, the listener should be registered - FutureUtils.complete(watchFuture, null); - assertNotNull(regListenerRef); - - // once the controller is resumed, it should start processing server change - // but since there is no servers available, the storage controller will not compute any ideal state - // for the assignment and `lastSuccessfulAssignmentAt` will remain negative. - assertFalse(coordSem.tryAcquire(1, TimeUnit.SECONDS)); - assertTrue(clusterController.getLastSuccessfulAssigmentAt() < 0); - - // notify the registration client that a new host is added - Set cluster = Sets.newSet(BookieId.parse("127.0.0.1:4181")); - Version version = new LongVersion(0L); - - regListenerRef.get().onBookiesChanged(new Versioned<>(cluster, version)); - // the cluster controller will be notified with cluster change and storage controller will compute - // the assignment state. cluster metadata store should be used for updating cluster assignment data. - coordSem.acquire(); - assertTrue(clusterController.getLastSuccessfulAssigmentAt() > 0); - long lastSuccessfulAssignmentAt = clusterController.getLastSuccessfulAssigmentAt(); - - // notify the cluster controller with same cluster, cluster controller should not attempt to update - // the assignment - regListenerRef.get().onBookiesChanged(new Versioned<>(cluster, version)); - assertFalse(coordSem.tryAcquire(200, TimeUnit.MILLISECONDS)); - assertEquals(lastSuccessfulAssignmentAt, clusterController.getLastSuccessfulAssigmentAt()); - - // multiple hosts added and removed - cluster.add(BookieId.parse("127.0.0.1:4182")); - cluster.add(BookieId.parse("127.0.0.1:4183")); - cluster.add(BookieId.parse("127.0.0.1:4184")); - cluster.add(BookieId.parse("127.0.0.1:4185")); - version = new LongVersion(1L); - - regListenerRef.get().onBookiesChanged(new Versioned<>(cluster, version)); - // the cluster controller should update assignment data if cluster is changed - coordSem.acquire(); - assertTrue(clusterController.getLastSuccessfulAssigmentAt() > lastSuccessfulAssignmentAt); - lastSuccessfulAssignmentAt = clusterController.getLastSuccessfulAssigmentAt(); - - // if cluster information is changed to empty, cluster controller should not be eager to change - // the assignment. - regListenerRef.get().onBookiesChanged(new Versioned<>(Collections.emptySet(), new LongVersion(2L))); - assertFalse(coordSem.tryAcquire(1, TimeUnit.SECONDS)); - assertEquals(lastSuccessfulAssignmentAt, clusterController.getLastSuccessfulAssigmentAt()); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/InMemClusterMetadataStoreTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/InMemClusterMetadataStoreTest.java deleted file mode 100644 index 3da87914059..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/InMemClusterMetadataStoreTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.cluster; - -import static org.junit.Assert.assertEquals; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import lombok.Cleanup; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.cluster.ClusterAssignmentData; -import org.apache.bookkeeper.stream.proto.cluster.ClusterMetadata; -import org.apache.bookkeeper.stream.proto.cluster.ServerAssignmentData; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test {@link InMemClusterMetadataStore}. - */ -public class InMemClusterMetadataStoreTest { - - private static final int NUM_STORAGE_CONTAINERS = 1024; - - private InMemClusterMetadataStore store; - - @Before - public void setup() { - store = new InMemClusterMetadataStore(NUM_STORAGE_CONTAINERS); - } - - @After - public void teardown() { - if (null != store) { - store.close(); - } - } - - @Test - public void testUnitialized() { - assertEquals( - ClusterMetadata.newBuilder().setNumStorageContainers(NUM_STORAGE_CONTAINERS).build(), - store.getClusterMetadata()); - assertEquals( - ClusterAssignmentData.newBuilder().build(), - store.getClusterAssignmentData()); - } - - @Test - public void testInitialize() { - int numStorageContainers = 2048; - store.initializeCluster(numStorageContainers); - assertEquals( - ClusterMetadata.newBuilder().setNumStorageContainers(numStorageContainers).build(), - store.getClusterMetadata()); - assertEquals( - ClusterAssignmentData.newBuilder().build(), - store.getClusterAssignmentData()); - } - - @Test - public void testUpdateClusterMetadata() { - int numStorageContainers = 4096; - ClusterMetadata metadata = ClusterMetadata.newBuilder() - .setNumStorageContainers(numStorageContainers) - .build(); - store.updateClusterMetadata(metadata); - assertEquals(metadata, store.getClusterMetadata()); - } - - @Test - public void testUpdateClusterAssignmentData() { - ClusterAssignmentData assignmentData = ClusterAssignmentData.newBuilder() - .putServers( - "server-0", - ServerAssignmentData.newBuilder() - .addContainers(1L) - .addContainers(2L) - .build()) - .build(); - store.updateClusterAssignmentData(assignmentData); - assertEquals(assignmentData, store.getClusterAssignmentData()); - } - - @Test - public void testWatchClusterAssignmentData() { - ClusterAssignmentData assignmentData = ClusterAssignmentData.newBuilder() - .putServers( - "server-0", - ServerAssignmentData.newBuilder() - .addContainers(1L) - .addContainers(2L) - .build()) - .build(); - - @Cleanup("shutdown") - ExecutorService executor = Executors.newSingleThreadExecutor(); - CompletableFuture watchFuture = new CompletableFuture<>(); - - store.watchClusterAssignmentData(data -> { - FutureUtils.complete(watchFuture, null); - }, executor); - - store.updateClusterAssignmentData(assignmentData); - - watchFuture.join(); - assertEquals(assignmentData, store.getClusterAssignmentData()); - } - - @Test - public void testUnwatchClusterAssignmentData() throws Exception { - ClusterAssignmentData assignmentData = ClusterAssignmentData.newBuilder() - .putServers( - "server-0", - ServerAssignmentData.newBuilder() - .addContainers(1L) - .addContainers(2L) - .build()) - .build(); - - @Cleanup("shutdown") - ExecutorService executor = Executors.newSingleThreadExecutor(); - - CompletableFuture watchFuture = new CompletableFuture<>(); - CountDownLatch latch = new CountDownLatch(2); - - Consumer dataConsumer = ignored -> { - latch.countDown(); - FutureUtils.complete(watchFuture, null); - }; - - assertEquals(0, store.getNumWatchers()); - store.watchClusterAssignmentData(dataConsumer, executor); - assertEquals(1, store.getNumWatchers()); - store.updateClusterAssignmentData(assignmentData); - - watchFuture.join(); - assertEquals(1, latch.getCount()); - assertEquals(assignmentData, store.getClusterAssignmentData()); - - store.unwatchClusterAssignmentData(dataConsumer); - assertEquals(0, store.getNumWatchers()); - store.updateClusterAssignmentData(assignmentData); - - watchFuture.get(100, TimeUnit.MILLISECONDS); - assertEquals(1, latch.getCount()); - } -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorListenerTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorListenerTest.java deleted file mode 100644 index bebed2b88b4..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorListenerTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.cluster; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.apache.bookkeeper.stream.storage.api.cluster.ClusterControllerLeader; -import org.apache.curator.framework.CuratorFramework; -import org.junit.Test; - -/** - * Unit test {@link ZkClusterControllerLeaderSelectorListener}. - */ -public class ZkClusterControllerLeaderSelectorListenerTest { - - @Test - public void testTakeLeadership() throws Exception { - ClusterControllerLeader leaderLogic = mock(ClusterControllerLeader.class); - - ZkClusterControllerLeaderSelectorListener listener = new ZkClusterControllerLeaderSelectorListener(leaderLogic); - CuratorFramework curator = mock(CuratorFramework.class); - listener.takeLeadership(curator); - - // if the listener is taking the leadership, it should execute the leader logic - verify(leaderLogic, times(1)).processAsLeader(); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorTest.java deleted file mode 100644 index c072d004efa..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterControllerLeaderSelectorTest.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.cluster; - -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.stream.storage.api.cluster.ClusterControllerLeader; -import org.apache.curator.framework.CuratorFramework; -import org.apache.curator.framework.CuratorFrameworkFactory; -import org.apache.curator.framework.state.ConnectionState; -import org.apache.curator.retry.ExponentialBackoffRetry; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test of {@link ZkClusterControllerLeaderSelector}. - */ -@Slf4j -public class ZkClusterControllerLeaderSelectorTest extends ZooKeeperClusterTestCase { - - @Rule - public final TestName runtime = new TestName(); - - private CuratorFramework curatorClient; - private String zkRootPath; - private ZkClusterControllerLeaderSelector selector; - - @Before - public void setup() throws Exception { - curatorClient = CuratorFrameworkFactory.newClient( - zkServers, - new ExponentialBackoffRetry(200, 10, 5000)); - curatorClient.start(); - - zkRootPath = "/" + runtime.getMethodName(); - curatorClient.create().forPath(zkRootPath); - - selector = new ZkClusterControllerLeaderSelector(curatorClient, zkRootPath); - } - - @After - public void teardown() { - if (null != selector) { - selector.close(); - } - curatorClient.close(); - } - - @Test(expected = NullPointerException.class) - public void testStartBeforeInitialize() { - selector.start(); - } - - @Test - public void testLeaderElection() throws InterruptedException { - CountDownLatch leaderLatch = new CountDownLatch(1); - selector.initialize(new ClusterControllerLeader() { - @Override - public void processAsLeader() throws Exception { - log.info("Become leader"); - leaderLatch.countDown(); - try { - TimeUnit.SECONDS.sleep(Long.MAX_VALUE); - } catch (InterruptedException ie) { - log.info("Leadership is interrupted"); - Thread.currentThread().interrupt(); - } - log.info("Ended leadership"); - } - - @Override - public void suspend() { - - } - - @Override - public void resume() { - - } - }); - - selector.start(); - leaderLatch.await(); - assertTrue("Should successfully become leader", true); - - log.info("Ended test"); - } - - @Test - public void testStateChangedToLost() throws InterruptedException { - CountDownLatch leaderLatch = new CountDownLatch(1); - CountDownLatch interruptedLatch = new CountDownLatch(1); - selector.initialize(new ClusterControllerLeader() { - @Override - public void processAsLeader() throws Exception { - log.info("Become leader"); - leaderLatch.countDown(); - try { - TimeUnit.SECONDS.sleep(Long.MAX_VALUE); - } catch (InterruptedException ie) { - log.info("Leader is interrupted", ie); - Thread.currentThread().interrupt(); - interruptedLatch.countDown(); - } - } - - @Override - public void suspend() { - } - - @Override - public void resume() { - } - }); - - selector.start(); - - leaderLatch.await(); - - assertTrue("Should successfully become leader", true); - - selector.stateChanged(curatorClient, ConnectionState.LOST); - - interruptedLatch.await(); - - assertTrue("Leader should be interrupted", true); - } - - @Test - public void testStateChangedToSuspendedResumed() throws InterruptedException { - CountDownLatch leaderLatch = new CountDownLatch(1); - CountDownLatch suspendedLatch = new CountDownLatch(1); - CountDownLatch resumeLatch = new CountDownLatch(1); - selector.initialize(new ClusterControllerLeader() { - @Override - public void processAsLeader() throws Exception { - log.info("Become leader"); - leaderLatch.countDown(); - try { - TimeUnit.SECONDS.sleep(Long.MAX_VALUE); - } catch (InterruptedException ie) { - log.info("Leader is interrupted", ie); - Thread.currentThread().interrupt(); - } - } - - @Override - public void suspend() { - suspendedLatch.countDown(); - } - - @Override - public void resume() { - resumeLatch.countDown(); - } - }); - - selector.start(); - leaderLatch.await(); - assertTrue("Should successfully become leader", true); - - selector.stateChanged(curatorClient, ConnectionState.SUSPENDED); - suspendedLatch.await(); - - assertTrue("Leader should be suspended", true); - - selector.stateChanged(curatorClient, ConnectionState.RECONNECTED); - resumeLatch.await(); - - assertTrue("Leader should be resumed", true); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterMetadataStoreTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterMetadataStoreTest.java deleted file mode 100644 index 62dfe1eabf1..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/cluster/ZkClusterMetadataStoreTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.cluster; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.function.Consumer; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.cluster.ClusterAssignmentData; -import org.apache.bookkeeper.stream.proto.cluster.ClusterMetadata; -import org.apache.bookkeeper.stream.proto.cluster.ServerAssignmentData; -import org.apache.bookkeeper.stream.storage.exceptions.StorageRuntimeException; -import org.apache.curator.framework.CuratorFramework; -import org.apache.curator.framework.CuratorFrameworkFactory; -import org.apache.curator.retry.ExponentialBackoffRetry; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.KeeperException.Code; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test {@link ZkClusterMetadataStore}. - */ -@Slf4j -public class ZkClusterMetadataStoreTest extends ZooKeeperClusterTestCase { - - private static final int NUM_STORAGE_CONTAINERS = 1024; - - @Rule - public final TestName runtime = new TestName(); - - private CuratorFramework curatorClient; - private ZkClusterMetadataStore store; - - @Before - public void setup() { - curatorClient = CuratorFrameworkFactory.newClient( - zkServers, - new ExponentialBackoffRetry(200, 10, 5000)); - curatorClient.start(); - store = new ZkClusterMetadataStore(curatorClient, zkServers, "/" + runtime.getMethodName()); - assertTrue(store.initializeCluster(NUM_STORAGE_CONTAINERS)); - } - - @After - public void teardown() { - if (null != store) { - store.close(); - } - if (null != curatorClient) { - curatorClient.close(); - } - } - - @Test - public void testUnitialized() { - ZkClusterMetadataStore newStore = new ZkClusterMetadataStore( - curatorClient, zkServers, "/" + runtime.getMethodName() + "-new"); - - try { - newStore.getClusterMetadata(); - fail("Should fail to get cluster metadata if not initialized"); - } catch (StorageRuntimeException sre) { - assertTrue(sre.getCause() instanceof KeeperException); - KeeperException cause = (KeeperException) sre.getCause(); - assertEquals(Code.NONODE, cause.code()); - } - - try { - newStore.getClusterAssignmentData(); - fail("Should fail to get cluster assignment data if not initialized"); - } catch (StorageRuntimeException sre) { - assertTrue(sre.getCause() instanceof KeeperException); - KeeperException cause = (KeeperException) sre.getCause(); - assertEquals(Code.NONODE, cause.code()); - } - } - - @Test - public void testInitialize() { - int numStorageContainers = 2048; - assertFalse(store.initializeCluster(numStorageContainers)); - } - - @Test - public void testUpdateClusterMetadata() { - int numStorageContainers = 4096; - ClusterMetadata metadata = ClusterMetadata.newBuilder() - .setNumStorageContainers(numStorageContainers) - .build(); - store.updateClusterMetadata(metadata); - assertEquals(metadata, store.getClusterMetadata()); - } - - @Test - public void testUpdateClusterAssignmentData() { - ClusterAssignmentData assignmentData = ClusterAssignmentData.newBuilder() - .putServers( - "server-0", - ServerAssignmentData.newBuilder() - .addContainers(1L) - .addContainers(2L) - .build()) - .build(); - store.updateClusterAssignmentData(assignmentData); - assertEquals(assignmentData, store.getClusterAssignmentData()); - } - - @Test - public void testWatchClusterAssignmentData() { - ClusterAssignmentData assignmentData = ClusterAssignmentData.newBuilder() - .putServers( - "server-0", - ServerAssignmentData.newBuilder() - .addContainers(1L) - .addContainers(2L) - .build()) - .build(); - - @Cleanup("shutdown") - ExecutorService executor = Executors.newSingleThreadExecutor(); - CompletableFuture watchFuture = new CompletableFuture<>(); - - store.watchClusterAssignmentData(data -> { - FutureUtils.complete(watchFuture, null); - }, executor); - - store.updateClusterAssignmentData(assignmentData); - - watchFuture.join(); - assertEquals(assignmentData, store.getClusterAssignmentData()); - } - - @Test - public void testUnwatchClusterAssignmentData() throws Exception { - ClusterAssignmentData assignmentData = ClusterAssignmentData.newBuilder() - .putServers( - "server-0", - ServerAssignmentData.newBuilder() - .addContainers(1L) - .addContainers(2L) - .build()) - .build(); - - @Cleanup("shutdown") - ExecutorService executor = Executors.newSingleThreadExecutor(); - - CompletableFuture watchFuture = new CompletableFuture<>(); - CountDownLatch latch = new CountDownLatch(2); - - Consumer dataConsumer = ignored -> { - log.info("Notify cluster assignment data changed"); - latch.countDown(); - FutureUtils.complete(watchFuture, null); - }; - - assertEquals(0, store.getNumWatchers()); - store.watchClusterAssignmentData(dataConsumer, executor); - assertEquals(1, store.getNumWatchers()); - store.updateClusterAssignmentData(assignmentData); - - watchFuture.join(); - assertEquals(1, latch.getCount()); - assertEquals(assignmentData, store.getClusterAssignmentData()); - - store.unwatchClusterAssignmentData(dataConsumer); - assertEquals(0, store.getNumWatchers()); - } -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java deleted file mode 100644 index 3f87b9e9d5b..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.grpc; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService; -import org.junit.Test; - -/** - * Unit test for {@link TestGrpcMetaRangeService}. - */ -public class TestGrpcMetaRangeService { - - private static final Throwable CAUSE = new Exception("test-exception"); - - // - // Meta KeyRange Server Requests tests - // - - @Test - public void testGetActiveRangesSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService); - - GetActiveRangesRequest request = GetActiveRangesRequest - .newBuilder() - .setStreamId(23456L) - .build(); - - GetActiveRangesResponse response = GetActiveRangesResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .build(); - - when(rangeService.getActiveRanges(request)).thenReturn( - CompletableFuture.completedFuture(response)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.getActiveRanges( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).getActiveRanges(request); - } - - @Test - public void testGetActiveRangesFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService); - - GetActiveRangesRequest request = GetActiveRangesRequest - .newBuilder() - .setStreamId(23456L) - .build(); - - GetActiveRangesResponse response = GetActiveRangesResponse.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .build(); - - when(rangeService.getActiveRanges(request)).thenReturn( - FutureUtils.exception(CAUSE)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.getActiveRanges( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).getActiveRanges(request); - } - - @Test - public void testGetActiveRangesException() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService); - - GetActiveRangesRequest request = GetActiveRangesRequest - .newBuilder() - .setStreamId(23456L) - .build(); - - when(rangeService.getActiveRanges(request)).thenReturn( - FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND))); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.getActiveRanges( - request, - responseObserver); - - responseObserver.verifyException(Status.NOT_FOUND); - verify(rangeService, times(1)).getActiveRanges(request); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java deleted file mode 100644 index f22e52ae1b5..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java +++ /dev/null @@ -1,618 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.grpc; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateStreamRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteStreamRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetStreamRequest; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.grpc.stub.StreamObserver; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.StreamName; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService; -import org.apache.bookkeeper.stream.storage.exceptions.StorageException; -import org.junit.Test; - -/** - * Unit test for {@link GrpcRootRangeService}. - */ -public class TestGrpcRootRangeService { - - private static final long colId = 12345L; - private static final String nsName = "test-namespace-name"; - private static final NamespaceConfiguration namespaceConf = - NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - private static final NamespaceProperties namespaceProps = - NamespaceProperties.newBuilder() - .setNamespaceId(colId) - .setNamespaceName(nsName) - .setDefaultStreamConf(namespaceConf.getDefaultStreamConf()) - .build(); - private static final String streamName = "test-stream-name"; - private static final StreamProperties streamProps = - StreamProperties.newBuilder() - .setStorageContainerId(1234L) - .setStreamConf(DEFAULT_STREAM_CONF) - .setStreamName(streamName) - .setStreamId(1234L) - .build(); - - private static final Throwable CAUSE = new StorageException("test-grpc-root-range-service"); - - // - // Test Namespace API - // - - @Test - public void testCreateNamespaceSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - CreateNamespaceResponse createResp = CreateNamespaceResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setNsProps(namespaceProps) - .build(); - CreateNamespaceRequest createReq = createCreateNamespaceRequest(nsName, namespaceConf); - when(rangeService.createNamespace(createReq)).thenReturn( - CompletableFuture.completedFuture(createResp)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(CreateNamespaceResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.createNamespace( - CreateNamespaceRequest.newBuilder() - .setName(nsName) - .setNsConf(namespaceConf) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertTrue(createResp == resultHolder.get()); - verify(rangeService, times(1)).createNamespace(createReq); - } - - @Test - public void testCreateNamespaceFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - CreateNamespaceResponse createResp = CreateNamespaceResponse.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .build(); - CreateNamespaceRequest createReq = createCreateNamespaceRequest(nsName, namespaceConf); - when(rangeService.createNamespace(createReq)).thenReturn( - FutureUtils.exception(CAUSE)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(CreateNamespaceResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.createNamespace( - CreateNamespaceRequest.newBuilder() - .setName(nsName) - .setNsConf(namespaceConf) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertEquals(createResp, resultHolder.get()); - verify(rangeService, times(1)).createNamespace(createReq); - } - - @Test - public void testDeleteNamespaceSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - DeleteNamespaceResponse deleteResp = DeleteNamespaceResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .build(); - DeleteNamespaceRequest deleteReq = createDeleteNamespaceRequest(nsName); - when(rangeService.deleteNamespace(deleteReq)).thenReturn( - CompletableFuture.completedFuture(deleteResp)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(DeleteNamespaceResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.deleteNamespace( - DeleteNamespaceRequest.newBuilder() - .setName(nsName) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertTrue(deleteResp == resultHolder.get()); - verify(rangeService, times(1)).deleteNamespace(deleteReq); - } - - @Test - public void testDeleteNamespaceFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - DeleteNamespaceResponse deleteResp = DeleteNamespaceResponse.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .build(); - DeleteNamespaceRequest deleteReq = createDeleteNamespaceRequest(nsName); - when(rangeService.deleteNamespace(deleteReq)).thenReturn( - FutureUtils.exception(CAUSE)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(DeleteNamespaceResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.deleteNamespace( - DeleteNamespaceRequest.newBuilder() - .setName(nsName) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertEquals(deleteResp, resultHolder.get()); - verify(rangeService, times(1)).deleteNamespace(deleteReq); - } - - @Test - public void testGetNamespaceSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - GetNamespaceResponse getResp = GetNamespaceResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setNsProps(namespaceProps) - .build(); - GetNamespaceRequest getReq = createGetNamespaceRequest(nsName); - when(rangeService.getNamespace(getReq)).thenReturn( - CompletableFuture.completedFuture(getResp)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(GetNamespaceResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.getNamespace( - GetNamespaceRequest.newBuilder() - .setName(nsName) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertTrue(getResp == resultHolder.get()); - verify(rangeService, times(1)).getNamespace(getReq); - } - - @Test - public void testGetNamespaceFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - GetNamespaceResponse getResp = GetNamespaceResponse.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .build(); - GetNamespaceRequest getReq = createGetNamespaceRequest(nsName); - when(rangeService.getNamespace(getReq)).thenReturn( - FutureUtils.exception(CAUSE)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(GetNamespaceResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.getNamespace( - GetNamespaceRequest.newBuilder() - .setName(nsName) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertEquals(getResp, resultHolder.get()); - verify(rangeService, times(1)).getNamespace(getReq); - } - - // - // Test Stream API - // - - @Test - public void testCreateStreamSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - CreateStreamResponse createResp = CreateStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setStreamProps(streamProps) - .build(); - CreateStreamRequest createReq = createCreateStreamRequest(nsName, streamName, DEFAULT_STREAM_CONF); - when(rangeService.createStream(createReq)).thenReturn( - CompletableFuture.completedFuture(createResp)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(CreateStreamResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.createStream( - CreateStreamRequest.newBuilder() - .setNsName(nsName) - .setName(streamName) - .setStreamConf(DEFAULT_STREAM_CONF) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertTrue(createResp == resultHolder.get()); - verify(rangeService, times(1)).createStream(createReq); - } - - @Test - public void testCreateStreamFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - CreateStreamResponse createResp = CreateStreamResponse.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .build(); - CreateStreamRequest createReq = createCreateStreamRequest(nsName, streamName, DEFAULT_STREAM_CONF); - when(rangeService.createStream(createReq)).thenReturn( - FutureUtils.exception(CAUSE)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(CreateStreamResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.createStream( - CreateStreamRequest.newBuilder() - .setNsName(nsName) - .setName(streamName) - .setStreamConf(DEFAULT_STREAM_CONF) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertEquals(createResp, resultHolder.get()); - verify(rangeService, times(1)).createStream(createReq); - } - - @Test - public void testDeleteStreamSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - DeleteStreamResponse deleteResp = DeleteStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .build(); - DeleteStreamRequest deleteReq = createDeleteStreamRequest(nsName, streamName); - when(rangeService.deleteStream(deleteReq)).thenReturn( - CompletableFuture.completedFuture(deleteResp)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(DeleteStreamResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.deleteStream( - DeleteStreamRequest.newBuilder() - .setNsName(nsName) - .setName(streamName) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertTrue(deleteResp == resultHolder.get()); - verify(rangeService, times(1)).deleteStream(deleteReq); - } - - @Test - public void testDeleteStreamFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - DeleteStreamResponse deleteResp = DeleteStreamResponse.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .build(); - DeleteStreamRequest deleteReq = createDeleteStreamRequest(nsName, streamName); - when(rangeService.deleteStream(deleteReq)).thenReturn( - FutureUtils.exception(CAUSE)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(DeleteStreamResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.deleteStream( - DeleteStreamRequest.newBuilder() - .setNsName(nsName) - .setName(streamName) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertEquals(deleteResp, resultHolder.get()); - verify(rangeService, times(1)).deleteStream(deleteReq); - } - - @Test - public void testGetStreamSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - GetStreamResponse getResp = GetStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setStreamProps(streamProps) - .build(); - GetStreamRequest getReq = createGetStreamRequest(nsName, streamName); - when(rangeService.getStream(getReq)).thenReturn( - CompletableFuture.completedFuture(getResp)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(GetStreamResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.getStream( - GetStreamRequest.newBuilder() - .setStreamName(StreamName.newBuilder() - .setNamespaceName(nsName) - .setStreamName(streamName)) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertTrue(getResp == resultHolder.get()); - verify(rangeService, times(1)).getStream(getReq); - } - - @Test - public void testGetStreamFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService); - GetStreamResponse getResp = GetStreamResponse.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .build(); - GetStreamRequest getReq = createGetStreamRequest(nsName, streamName); - when(rangeService.getStream(getReq)).thenReturn( - FutureUtils.exception(CAUSE)); - AtomicReference resultHolder = new AtomicReference<>(); - AtomicReference exceptionHolder = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - StreamObserver streamObserver = new StreamObserver() { - @Override - public void onNext(GetStreamResponse resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - }; - grpcService.getStream( - GetStreamRequest.newBuilder() - .setStreamName(StreamName.newBuilder() - .setNamespaceName(nsName) - .setStreamName(streamName)) - .build(), - streamObserver); - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertEquals(getResp, resultHolder.get()); - verify(rangeService, times(1)).getStream(getReq); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java deleted file mode 100644 index 874e69ba376..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.grpc; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.protobuf.ByteString; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService; -import org.junit.Test; - -/** - * Unit test for {@link TestGrpcTableService}. - */ -public class TestGrpcTableService { - - private static final Throwable CAUSE = new Exception("test-exception"); - - private static final ByteString TEST_ROUTING_KEY = ByteString.copyFromUtf8("test-routing-key"); - private static final RoutingHeader ROUTING_HEADER = RoutingHeader.newBuilder() - .setStreamId(1234L) - .setRangeId(1234L) - .setRKey(TEST_ROUTING_KEY) - .build(); - private static final ByteString TEST_KEY = ByteString.copyFromUtf8("test-key"); - private static final ByteString TEST_VAL = ByteString.copyFromUtf8("test-val"); - - // - // Meta KeyRange Server Requests tests - // - - @Test - public void testPutSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - PutRequest request = PutRequest - .newBuilder() - .setKey(TEST_KEY) - .setValue(TEST_VAL) - .setHeader(ROUTING_HEADER) - .build(); - - PutResponse response = PutResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(ROUTING_HEADER) - .build()) - .build(); - - when(rangeService.put(request)).thenReturn( - CompletableFuture.completedFuture(response)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.put( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).put(request); - } - - @Test - public void testPutFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - PutRequest request = PutRequest - .newBuilder() - .setKey(TEST_KEY) - .setValue(TEST_VAL) - .setHeader(ROUTING_HEADER) - .build(); - - PutResponse response = PutResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .setRoutingHeader(ROUTING_HEADER) - .build()) - .build(); - - when(rangeService.put(request)).thenReturn( - FutureUtils.exception(CAUSE)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.put( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).put(request); - } - - @Test - public void testPutException() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - PutRequest request = PutRequest - .newBuilder() - .setKey(TEST_KEY) - .setValue(TEST_VAL) - .setHeader(ROUTING_HEADER) - .build(); - - when(rangeService.put(request)).thenReturn( - FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND))); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.put( - request, - responseObserver); - - responseObserver.verifyException(Status.NOT_FOUND); - verify(rangeService, times(1)).put(request); - } - - @Test - public void testRangeSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - RangeRequest request = RangeRequest - .newBuilder() - .setKey(TEST_KEY) - .setHeader(ROUTING_HEADER) - .build(); - - RangeResponse response = RangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(ROUTING_HEADER) - .build()) - .build(); - - when(rangeService.range(request)).thenReturn( - CompletableFuture.completedFuture(response)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.range( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).range(request); - } - - @Test - public void testRangeActiveRangesFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - RangeRequest request = RangeRequest - .newBuilder() - .setKey(TEST_KEY) - .setHeader(ROUTING_HEADER) - .build(); - - RangeResponse response = RangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .setRoutingHeader(ROUTING_HEADER) - .build()) - .build(); - - when(rangeService.range(request)).thenReturn( - FutureUtils.exception(CAUSE)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.range( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).range(request); - } - - @Test - public void testRangeActiveRangesException() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - RangeRequest request = RangeRequest - .newBuilder() - .setKey(TEST_KEY) - .setHeader(ROUTING_HEADER) - .build(); - - when(rangeService.range(request)).thenReturn( - FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND))); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.range( - request, - responseObserver); - - responseObserver.verifyException(Status.NOT_FOUND); - verify(rangeService, times(1)).range(request); - } - - @Test - public void testDeleteSuccess() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - DeleteRangeRequest request = DeleteRangeRequest - .newBuilder() - .setKey(TEST_KEY) - .setHeader(ROUTING_HEADER) - .build(); - - DeleteRangeResponse response = DeleteRangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(ROUTING_HEADER) - .build()) - .build(); - - when(rangeService.delete(request)).thenReturn( - CompletableFuture.completedFuture(response)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.delete( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).delete(request); - } - - @Test - public void testDeleteFailure() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - DeleteRangeRequest request = DeleteRangeRequest - .newBuilder() - .setKey(TEST_KEY) - .setHeader(ROUTING_HEADER) - .build(); - - DeleteRangeResponse response = DeleteRangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.INTERNAL_SERVER_ERROR) - .setRoutingHeader(ROUTING_HEADER) - .build()) - .build(); - - when(rangeService.delete(request)).thenReturn( - FutureUtils.exception(CAUSE)); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.delete( - request, - responseObserver); - - responseObserver.verifySuccess(response); - verify(rangeService, times(1)).delete(request); - } - - @Test - public void testDeleteException() throws Exception { - RangeStoreService rangeService = mock(RangeStoreService.class); - GrpcTableService grpcService = new GrpcTableService(rangeService); - - DeleteRangeRequest request = DeleteRangeRequest - .newBuilder() - .setKey(TEST_KEY) - .setHeader(ROUTING_HEADER) - .build(); - - when(rangeService.delete(request)).thenReturn( - FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND))); - - TestResponseObserver responseObserver = - new TestResponseObserver<>(); - grpcService.delete( - request, - responseObserver); - - responseObserver.verifyException(Status.NOT_FOUND); - verify(rangeService, times(1)).delete(request); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestResponseObserver.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestResponseObserver.java deleted file mode 100644 index 7fae6948d75..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestResponseObserver.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.grpc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import io.grpc.Status; -import io.grpc.StatusException; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Response Observer used for testing. - */ -public class TestResponseObserver implements StreamObserver { - - private final AtomicReference resultHolder = - new AtomicReference<>(); - private final AtomicReference exceptionHolder = - new AtomicReference<>(); - private final CountDownLatch latch = new CountDownLatch(1); - - @Override - public void onNext(RespT resp) { - resultHolder.set(resp); - } - - @Override - public void onError(Throwable t) { - exceptionHolder.set(t); - latch.countDown(); - } - - @Override - public void onCompleted() { - latch.countDown(); - } - - public RespT get() throws Throwable { - latch.await(); - if (null != exceptionHolder.get()) { - throw exceptionHolder.get(); - } - return resultHolder.get(); - } - - public void verifySuccess(RespT resp) throws Exception { - latch.await(); - assertNull(exceptionHolder.get()); - assertNotNull(resultHolder.get()); - assertEquals(resp, resultHolder.get()); - } - - public void verifyException(Status status) throws Exception { - latch.await(); - assertNull(resultHolder.get()); - assertNotNull(exceptionHolder.get()); - assertTrue( - exceptionHolder.get() instanceof StatusRuntimeException - || exceptionHolder.get() instanceof StatusException); - if (exceptionHolder.get() instanceof StatusRuntimeException) { - assertEquals(status, ((StatusRuntimeException) exceptionHolder.get()).getStatus()); - } else if (exceptionHolder.get() instanceof StatusException) { - assertEquals(status, ((StatusException) exceptionHolder.get()).getStatus()); - } - } -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreCacheTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreCacheTest.java deleted file mode 100644 index dd775b8663d..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreCacheTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.kv; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore; -import org.apache.bookkeeper.stream.protocol.RangeId; -import org.apache.bookkeeper.stream.storage.api.kv.TableStore; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link TableStoreCache}. - */ -public class TableStoreCacheTest { - - private static final long SCID = 3456L; - private static final RangeId RID = RangeId.of(1234L, 3456L); - - private MVCCStoreFactory factory; - private TableStoreCache storeCache; - - @Before - public void setUp() { - this.factory = mock(MVCCStoreFactory.class); - this.storeCache = new TableStoreCache(this.factory); - } - - @Test - public void testGetTableStoreWithoutOpen() { - assertNull(storeCache.getTableStore(RID)); - assertTrue(storeCache.getTableStores().isEmpty()); - assertTrue(storeCache.getTableStoresOpening().isEmpty()); - } - - @SuppressWarnings("unchecked") - @Test - public void testOpenTableStoreSuccessWhenStoreIsNotCached() throws Exception { - assertNull(storeCache.getTableStore(RID)); - assertTrue(storeCache.getTableStores().isEmpty()); - assertTrue(storeCache.getTableStoresOpening().isEmpty()); - - MVCCAsyncStore mvccStore = mock(MVCCAsyncStore.class); - when(factory.openStore(eq(SCID), eq(RID.getStreamId()), eq(RID.getRangeId()), anyInt())) - .thenReturn(FutureUtils.value(mvccStore)); - TableStore store = FutureUtils.result(storeCache.openTableStore(SCID, RID, 0)); - assertEquals(1, storeCache.getTableStores().size()); - assertEquals(0, storeCache.getTableStoresOpening().size()); - assertTrue(storeCache.getTableStores().containsKey(RID)); - assertSame(store, storeCache.getTableStores().get(RID)); - } - - @Test - public void testOpenTableStoreFailureWhenStoreIsNotCached() throws Exception { - assertNull(storeCache.getTableStore(RID)); - assertTrue(storeCache.getTableStores().isEmpty()); - assertTrue(storeCache.getTableStoresOpening().isEmpty()); - - Exception cause = new Exception("Failure"); - when(factory.openStore(eq(SCID), eq(RID.getStreamId()), eq(RID.getRangeId()), anyInt())) - .thenReturn(FutureUtils.exception(cause)); - try { - FutureUtils.result(storeCache.openTableStore(SCID, RID, 0)); - fail("Should fail to open table if the underlying factory fails to open a local store"); - } catch (Exception ee) { - assertSame(cause, ee); - } - assertEquals(0, storeCache.getTableStores().size()); - assertEquals(0, storeCache.getTableStoresOpening().size()); - } - - @Test - public void testOpenTableStoreWhenStoreIsCached() throws Exception { - TableStore store = mock(TableStore.class); - storeCache.getTableStores().put(RID, store); - - assertSame(store, storeCache.getTableStore(RID)); - assertSame(store, FutureUtils.result(storeCache.openTableStore(SCID, RID, 0))); - } - - @SuppressWarnings("unchecked") - @Test - public void testConcurrentOpenTableStore() throws Exception { - MVCCAsyncStore mvccStore1 = mock(MVCCAsyncStore.class); - MVCCAsyncStore mvccStore2 = mock(MVCCAsyncStore.class); - CompletableFuture> future1 = FutureUtils.createFuture(); - CompletableFuture> future2 = FutureUtils.createFuture(); - when(factory.openStore(eq(SCID), eq(RID.getStreamId()), eq(RID.getRangeId()), anyInt())) - .thenReturn(future1) - .thenReturn(future2); - - CompletableFuture openFuture1 = - storeCache.openTableStore(SCID, RID, 0); - assertEquals(0, storeCache.getTableStores().size()); - assertEquals(1, storeCache.getTableStoresOpening().size()); - CompletableFuture openFuture2 = - storeCache.openTableStore(SCID, RID, 0); - assertEquals(0, storeCache.getTableStores().size()); - assertEquals(1, storeCache.getTableStoresOpening().size()); - assertSame(openFuture1, openFuture2); - - future1.complete(mvccStore1); - future1.complete(mvccStore2); - - TableStore store1 = FutureUtils.result(openFuture1); - TableStore store2 = FutureUtils.result(openFuture2); - assertSame(store1, store2); - assertEquals(0, storeCache.getTableStoresOpening().size()); - assertEquals(1, storeCache.getTableStores().size()); - assertSame(store1, storeCache.getTableStores().get(RID)); - - verify(factory, times(1)) - .openStore(eq(SCID), eq(RID.getStreamId()), eq(RID.getRangeId()), anyInt()); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java deleted file mode 100644 index 2c7124f8ef4..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.kv; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import com.google.protobuf.ByteString; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.kv.KeyValue; -import org.apache.bookkeeper.stream.proto.kv.rpc.Compare; -import org.apache.bookkeeper.stream.proto.kv.rpc.Compare.CompareResult; -import org.apache.bookkeeper.stream.proto.kv.rpc.Compare.CompareTarget; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.RequestOp; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseOp; -import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCAsyncStoreTestBase; -import org.junit.Test; - -/** - * Unit test of {@link TableStoreImpl}. - */ -@Slf4j -public class TableStoreImplTest extends MVCCAsyncStoreTestBase { - - private static final long SC_ID = 123L; - private static final ByteString RKEY = ByteString.copyFromUtf8("routing-key"); - private static final RoutingHeader HEADER = RoutingHeader.newBuilder() - .setRangeId(1234L) - .setRKey(RKEY) - .setStreamId(1256L) - .build(); - - private TableStoreImpl tableStore; - - @Override - protected void doSetup() throws Exception { - this.tableStore = new TableStoreImpl(store); - } - - @Override - protected void doTeardown() throws Exception { - } - - // - // Put & Range Ops - // - - private static ByteString getKey(int i) { - return ByteString.copyFromUtf8(String.format("key-%05d", i)); - } - - private ByteString getValue(int i) { - return ByteString.copyFromUtf8(String.format("value-%05d", i)); - } - - private List writeKVs(int numPairs, boolean prevKv) throws Exception { - List> results = - Lists.newArrayListWithExpectedSize(numPairs); - for (int i = 0; i < numPairs; i++) { - results.add(writeKV(i, prevKv)); - } - return Lists.transform( - result(FutureUtils.collect(results)), putResp -> { - assertEquals(StatusCode.SUCCESS, putResp.getHeader().getCode()); - assertEquals(HEADER, putResp.getHeader().getRoutingHeader()); - if (putResp.hasPrevKv()) { - return putResp.getPrevKv(); - } else { - return null; - } - }); - } - - private CompletableFuture writeKV(int i, boolean prevKv) { - return tableStore.put(PutRequest.newBuilder() - .setKey(getKey(i)) - .setValue(getValue(i)) - .setHeader(HEADER) - .setPrevKv(prevKv) - .build()); - } - - RangeResponse getKeyFromTableStore(int i) throws Exception { - return result( - tableStore.range(RangeRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(i)) - .build())); - } - - KeyValue getKeyValue(int i) throws Exception { - RangeResponse rr = getKeyFromTableStore(i); - assertEquals(StatusCode.SUCCESS, rr.getHeader().getCode()); - assertEquals(HEADER, rr.getHeader().getRoutingHeader()); - assertFalse(rr.getMore()); - if (0 == rr.getCount()) { - return null; - } else { - return rr.getKvs(0); - } - } - - void putKeyToTableStore(int key, int value) throws Exception { - PutResponse putResp = result( - tableStore.put(PutRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .setValue(getValue(value)) - .build())); - - assertEquals(StatusCode.SUCCESS, putResp.getHeader().getCode()); - assertEquals(HEADER, putResp.getHeader().getRoutingHeader()); - assertFalse(putResp.hasPrevKv()); - } - - KeyValue putIfAbsentToTableStore(int key, int value, boolean expectedSuccess) throws Exception { - TxnResponse txnResp = result( - tableStore.txn(TxnRequest.newBuilder() - .setHeader(HEADER) - .addCompare(Compare.newBuilder() - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.VALUE) - .setKey(getKey(key)) - .setValue(ByteString.copyFrom(new byte[0]))) - .addSuccess(RequestOp.newBuilder() - .setRequestPut(PutRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .setValue(getValue(value)) - .setPrevKv(true) - .build())) - .addFailure(RequestOp.newBuilder() - .setRequestRange(RangeRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .build())) - .build())); - - assertEquals(HEADER, txnResp.getHeader().getRoutingHeader()); - assertEquals(StatusCode.SUCCESS, txnResp.getHeader().getCode()); - - ResponseOp respOp = txnResp.getResponses(0); - if (expectedSuccess) { - assertTrue(txnResp.getSucceeded()); - PutResponse putResp = respOp.getResponsePut(); - assertEquals(HEADER, putResp.getHeader().getRoutingHeader()); - if (!putResp.hasPrevKv()) { - return null; - } - return putResp.getPrevKv(); - } else { - assertFalse(txnResp.getSucceeded()); - RangeResponse rangeResp = respOp.getResponseRange(); - if (rangeResp.getCount() == 0) { - return null; - } else { - assertEquals(1, rangeResp.getCount()); - return rangeResp.getKvs(0); - } - } - } - - TxnResponse vPutToTableStore(int key, int value, long version) - throws Exception { - return result( - tableStore.txn(TxnRequest.newBuilder() - .setHeader(HEADER) - .addCompare(Compare.newBuilder() - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.VERSION) - .setKey(getKey(key)) - .setVersion(version)) - .addSuccess(RequestOp.newBuilder() - .setRequestPut(PutRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .setValue(getValue(value)) - .setPrevKv(true) - .build())) - .addFailure(RequestOp.newBuilder() - .setRequestRange(RangeRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .build())) - .build())); - } - - KeyValue verifyVPutResponse(TxnResponse txnResp, boolean expectedSuccess) throws Exception { - assertEquals(HEADER, txnResp.getHeader().getRoutingHeader()); - assertEquals(StatusCode.SUCCESS, txnResp.getHeader().getCode()); - - ResponseOp respOp = txnResp.getResponses(0); - if (expectedSuccess) { - assertTrue(txnResp.getSucceeded()); - PutResponse putResp = respOp.getResponsePut(); - assertEquals(HEADER, putResp.getHeader().getRoutingHeader()); - if (!putResp.hasPrevKv()) { - return null; - } - return putResp.getPrevKv(); - } else { - assertFalse(txnResp.getSucceeded()); - RangeResponse rangeResp = respOp.getResponseRange(); - if (rangeResp.getCount() == 0) { - return null; - } else { - assertEquals(1, rangeResp.getCount()); - return rangeResp.getKvs(0); - } - } - } - - TxnResponse rPutToTableStore(int key, int value, long revision) - throws Exception { - return result( - tableStore.txn(TxnRequest.newBuilder() - .setHeader(HEADER) - .addCompare(Compare.newBuilder() - .setResult(CompareResult.EQUAL) - .setTarget(CompareTarget.MOD) - .setKey(getKey(key)) - .setModRevision(revision)) - .addSuccess(RequestOp.newBuilder() - .setRequestPut(PutRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .setValue(getValue(value)) - .setPrevKv(true) - .build())) - .addFailure(RequestOp.newBuilder() - .setRequestRange(RangeRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .build())) - .build())); - } - - KeyValue deleteKeyFromTableStore(int key) throws Exception { - DeleteRangeResponse response = result( - tableStore.delete(DeleteRangeRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(key)) - .setPrevKv(true) - .build())); - - assertEquals(StatusCode.SUCCESS, response.getHeader().getCode()); - assertEquals(HEADER, response.getHeader().getRoutingHeader()); - if (0 == response.getPrevKvsCount()) { - return null; - } else { - return response.getPrevKvs(0); - } - } - - List deleteRange(int startKey, int endKey) throws Exception { - DeleteRangeResponse delResp = result( - tableStore.delete(DeleteRangeRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(startKey)) - .setRangeEnd(getKey(endKey)) - .setPrevKv(true) - .build())); - - assertEquals(StatusCode.SUCCESS, delResp.getHeader().getCode()); - assertEquals(HEADER, delResp.getHeader().getRoutingHeader()); - return delResp.getPrevKvsList(); - } - - List range(int startKey, int endKey) throws Exception { - RangeResponse rangeResp = result( - tableStore.range(RangeRequest.newBuilder() - .setHeader(HEADER) - .setKey(getKey(startKey)) - .setRangeEnd(getKey(endKey)) - .build())); - - assertEquals(StatusCode.SUCCESS, rangeResp.getHeader().getCode()); - assertEquals(HEADER, rangeResp.getHeader().getRoutingHeader()); - return rangeResp.getKvsList(); - } - - @Test - public void testBasicOps() throws Exception { - // normal put - { - // get key(0) - KeyValue kv = getKeyValue(0); - assertNull(kv); - // put key(0), value(0) - putKeyToTableStore(0, 0); - // get key(0) again - kv = getKeyValue(0); - assertEquals(getKey(0), kv.getKey()); - assertEquals(getValue(0), kv.getValue()); - } - - // putIfAbsent - { - // failure case - KeyValue prevKV = putIfAbsentToTableStore(0, 99, false); - assertNotNull(prevKV); - assertEquals(getKey(0), prevKV.getKey()); - assertEquals(getValue(0), prevKV.getValue()); - // get key(0) - KeyValue kv = getKeyValue(0); - assertEquals(getKey(0), kv.getKey()); - assertEquals(getValue(0), kv.getValue()); - // success case - prevKV = putIfAbsentToTableStore(1, 1, true); - assertNull(prevKV); - // get key(1) - kv = getKeyValue(1); - assertEquals(getKey(1), kv.getKey()); - assertEquals(getValue(1), kv.getValue()); - } - - // vPut - { - // key-not-found case - int key = 2; - int initialVal = 2; - int casVal = 99; - TxnResponse response = vPutToTableStore(key, initialVal, 100L); - assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode()); - - // vPut(k, v, -1L) - response = vPutToTableStore(key, initialVal, -1L); - assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode()); - // put(key2, v) - KeyValue prevKV = putIfAbsentToTableStore(key, initialVal, true); - assertNull(prevKV); - // vPut(key2, v, 0) - response = vPutToTableStore(key, casVal, 0); - assertEquals(StatusCode.SUCCESS, response.getHeader().getCode()); - prevKV = verifyVPutResponse(response, true); - assertNotNull(prevKV); - assertEquals(getKey(key), prevKV.getKey()); - assertEquals(getValue(initialVal), prevKV.getValue()); - assertEquals(0, prevKV.getVersion()); - - KeyValue kv = getKeyValue(key); - assertEquals(getKey(key), kv.getKey()); - assertEquals(getValue(casVal), kv.getValue()); - } - - // rPut - { - // key-not-found case - int key = 3; - int initialVal = 3; - int casVal = 99; - - TxnResponse response = rPutToTableStore(key, initialVal, 100L); - assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode()); - - // rPut(k, v, -1L) - response = rPutToTableStore(key, initialVal, -1L); - assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode()); - - // put(key2, v) - KeyValue prevKV = putIfAbsentToTableStore(key, initialVal, true); - assertNull(prevKV); - - KeyValue kv = getKeyValue(key); - long revision = kv.getModRevision(); - assertEquals(getValue(initialVal), kv.getValue()); - - // rPut(key2, v, 0) - response = rPutToTableStore(key, casVal, revision); - assertEquals(StatusCode.SUCCESS, response.getHeader().getCode()); - - kv = getKeyValue(key); - assertEquals(revision + 1, kv.getModRevision()); - assertEquals(getValue(casVal), kv.getValue()); - } - - // delete(k) - { - // key not found - KeyValue kv = deleteKeyFromTableStore(99); - assertNull(kv); - // key exists - int key = 0; - kv = getKeyValue(key); - assertEquals(getKey(key), kv.getKey()); - assertEquals(getValue(key), kv.getValue()); - kv = deleteKeyFromTableStore(key); - assertNotNull(kv); - assertEquals(getKey(key), kv.getKey()); - assertEquals(getValue(key), kv.getValue()); - // the key/value pair should not exist after deletion. - kv = getKeyValue(key); - assertNull(kv); - } - - } - - @Test - public void testPutGetDeleteRanges() throws Exception { - int numPairs = 100; - List prevKvs = writeKVs(numPairs, true); - assertEquals(numPairs, prevKvs.size()); - - for (KeyValue prevKv : prevKvs) { - assertNull(prevKv); - } - - verifyRange(20, 70, 2, 2, 0); - - prevKvs = deleteRange(20, 70); - assertNotNull(prevKvs); - verifyRecords( - prevKvs, - 20, 70, - 2, 2, 0); - - prevKvs = range(20, 70); - assertTrue(prevKvs.isEmpty()); - } - - private void verifyRange(int startKey, - int endKey, - int startCreateRevision, - int startModRevision, - int expectedVersion) throws Exception { - int count = endKey - startKey + 1; - List kvs = range(startKey, endKey); - assertEquals(count, kvs.size()); - - verifyRecords(kvs, startKey, endKey, startCreateRevision, startModRevision, expectedVersion); - } - - private void verifyRecords(List kvs, - int startKey, int endKey, - int startCreateRevision, - int startModRevision, - int expectedVersion) { - int idx = startKey; - for (KeyValue kv : kvs) { - assertEquals(getKey(idx), kv.getKey()); - assertEquals(getValue(idx), kv.getValue()); - // revision - starts from 1, but the first revision is used for nop barrier record. - assertEquals(idx + startCreateRevision, kv.getCreateRevision()); - assertEquals(idx + startModRevision, kv.getModRevision()); - assertEquals(expectedVersion, kv.getVersion()); - ++idx; - } - assertEquals(endKey + 1, idx); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtilsTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtilsTest.java deleted file mode 100644 index dfdd69e50d1..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtilsTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.kv; - -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.HAS_ROUTING_KEY; -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.NO_ROUTING_KEY; -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.SEP; -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.getLKey; -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.handleCause; -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.hasRKey; -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.newKeyValue; -import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.newStoreKey; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.protobuf.ByteString; -import java.util.concurrent.ExecutionException; -import org.apache.bookkeeper.api.kv.result.Code; -import org.apache.bookkeeper.api.kv.result.KeyValue; -import org.apache.bookkeeper.statelib.api.exceptions.MVCCStoreException; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Unit test of {@link TableStoreUtils}. - */ -public class TableStoreUtilsTest { - - private final byte[] rKey = new byte[]{'a', 'b', 'c'}; - private final byte[] lKey = new byte[]{'d', 'e', 'e'}; - private final byte[] storeKeyWithRKey = new byte[]{ - HAS_ROUTING_KEY, - 'a', 'b', 'c', - SEP, - 'd', 'e', 'e' - }; - private final byte[] storeKeyWithoutRKey = new byte[]{ - NO_ROUTING_KEY, - 'd', 'e', 'e' - }; - private final byte[] value = new byte[]{'v', 'a', 'l', 'u', 'e'}; - - @Test - public void testHasRKey() { - assertFalse(hasRKey(null)); - assertFalse(hasRKey(ByteString.copyFrom(new byte[0]))); - assertTrue(hasRKey(ByteString.copyFromUtf8("test"))); - } - - @Test - public void testNewStoreKey() { - assertArrayEquals( - storeKeyWithRKey, - newStoreKey( - ByteString.copyFrom(rKey), - ByteString.copyFrom(lKey)) - ); - assertArrayEquals( - storeKeyWithoutRKey, - newStoreKey( - null, - ByteString.copyFrom(lKey)) - ); - } - - @Test - public void testGetLKey() { - assertEquals( - ByteString.copyFrom(lKey), - getLKey(storeKeyWithoutRKey, null)); - assertEquals( - ByteString.copyFrom(lKey), - getLKey(storeKeyWithRKey, ByteString.copyFrom(rKey))); - } - - @Test - public void testHandleCause() { - StatusCode[] protoCodes = new StatusCode[]{ - StatusCode.SUCCESS, - StatusCode.INTERNAL_SERVER_ERROR, - StatusCode.BAD_REQUEST, - StatusCode.BAD_REQUEST, - StatusCode.UNEXPECTED, - StatusCode.BAD_REVISION, - StatusCode.BAD_REVISION, - StatusCode.KEY_NOT_FOUND, - StatusCode.KEY_EXISTS, - }; - Code[] codes = new Code[]{ - Code.OK, - Code.INTERNAL_ERROR, - Code.INVALID_ARGUMENT, - Code.ILLEGAL_OP, - Code.UNEXPECTED, - Code.BAD_REVISION, - Code.SMALLER_REVISION, - Code.KEY_NOT_FOUND, - Code.KEY_EXISTS, - }; - - for (int i = 0; i < codes.length; i++) { - Code code = codes[i]; - MVCCStoreException exception = new MVCCStoreException(code, "test-" + code); - assertEquals(protoCodes[i], handleCause(exception)); - } - } - - @Test - public void testHandleUnknownCause() { - Exception exception = new Exception("test-unknown-cause"); - assertEquals(StatusCode.INTERNAL_SERVER_ERROR, handleCause(exception)); - } - - @Test - public void testHandleExecutionException() { - MVCCStoreException exception = new MVCCStoreException( - Code.BAD_REVISION, "bad-revision"); - ExecutionException ee = new ExecutionException(exception); - assertEquals(StatusCode.BAD_REVISION, handleCause(ee)); - } - - @SuppressWarnings("unchecked") - @Test - public void testNewKeyValue() { - long rid = System.currentTimeMillis(); - long createRev = 2 * System.currentTimeMillis(); - long modRev = 3 * System.currentTimeMillis(); - long version = 4 * System.currentTimeMillis(); - KeyValue kv = mock(KeyValue.class); - when(kv.key()).thenReturn(storeKeyWithRKey); - when(kv.value()).thenReturn(this.value); - when(kv.createRevision()).thenReturn(createRev); - when(kv.modifiedRevision()).thenReturn(modRev); - when(kv.version()).thenReturn(version); - - org.apache.bookkeeper.stream.proto.kv.KeyValue keyValue = - newKeyValue(ByteString.copyFrom(rKey), kv); - - assertEquals(ByteString.copyFrom(lKey), keyValue.getKey()); - assertEquals(ByteString.copyFrom(value), keyValue.getValue()); - assertEquals(createRev, keyValue.getCreateRevision()); - assertEquals(modRev, keyValue.getModRevision()); - assertEquals(version, keyValue.getVersion()); - } - - // - // TODO: add more test cases - // - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java deleted file mode 100644 index 5e5f4b3d7e8..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.metadata; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import java.util.Collections; -import java.util.List; -import java.util.NavigableMap; -import java.util.stream.LongStream; -import org.apache.bookkeeper.clients.impl.internal.api.StorageServerClientManager; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.RangeMetadata; -import org.apache.bookkeeper.stream.proto.RangeState; -import org.apache.bookkeeper.stream.proto.StreamMetadata.LifecycleState; -import org.apache.bookkeeper.stream.proto.StreamMetadata.ServingState; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse; -import org.apache.bookkeeper.stream.proto.storage.RelatedRanges; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.storage.impl.metadata.stream.MetaRangeImpl; -import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerPlacementPolicyImpl; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCAsyncStoreTestBase; -import org.junit.Test; - -/** - * Unit test of {@link MetaRangeStoreImplTest}. - */ -public class MetaRangeStoreImplTest extends MVCCAsyncStoreTestBase { - - private StreamProperties streamProps; - private MetaRangeStoreImpl mrStoreImpl; - private StorageServerClientManager clientManager; - - @Override - protected void doSetup() throws Exception { - this.streamProps = StreamProperties.newBuilder() - .setStorageContainerId(1234L) - .setStreamConf(DEFAULT_STREAM_CONF) - .setStreamName(name.getMethodName() + "_stream") - .setStreamId(System.currentTimeMillis()) - .build(); - this.clientManager = mock(StorageServerClientManager.class); - this.mrStoreImpl = new MetaRangeStoreImpl( - this.store, - StorageContainerPlacementPolicyImpl.of(1024), - this.scheduler.chooseThread(), - clientManager); - } - - @Override - protected void doTeardown() throws Exception { - } - - GetActiveRangesRequest createRequest(StreamProperties streamProperties) { - when(clientManager.getStreamProperties(eq(this.streamProps.getStreamId()))) - .thenReturn(FutureUtils.value(streamProperties)); - GetActiveRangesRequest.Builder reqBuilder = GetActiveRangesRequest.newBuilder() - .setStreamId(this.streamProps.getStreamId()); - return reqBuilder.build(); - } - - @Test - public void testCreateIfMissingPropsNotSpecified() throws Exception { - GetActiveRangesResponse resp = FutureUtils.result( - this.mrStoreImpl.getActiveRanges(createRequest(null))); - - assertEquals(StatusCode.STREAM_NOT_FOUND, resp.getCode()); - } - - @Test - public void testCreateIfMissing() throws Exception { - GetActiveRangesResponse resp = FutureUtils.result( - this.mrStoreImpl.getActiveRanges(createRequest(streamProps))); - - assertEquals(StatusCode.SUCCESS, resp.getCode()); - verifyGetResponse(resp); - } - - private void verifyGetResponse(GetActiveRangesResponse getResp) throws Exception { - MetaRangeImpl metaRange = new MetaRangeImpl( - this.store, - this.scheduler.chooseThread(), - StorageContainerPlacementPolicyImpl.of(1024)); - assertNotNull(FutureUtils.result(metaRange.load(streamProps.getStreamId()))); - verifyStreamMetadata(metaRange, streamProps); - - List rangesList = getResp.getRangesList(); - List currentRanges = metaRange.unsafeGetCurrentRanges(); - - assertEquals(currentRanges.size(), rangesList.size()); - for (int i = 0; i < rangesList.size(); i++) { - RelatedRanges actualRR = rangesList.get(i); - long expectedRid = currentRanges.get(i); - RangeMetadata expectedRangeMetadata = - metaRange.unsafeGetRanges().get(expectedRid); - assertNotNull(expectedRangeMetadata); - - assertEquals(Collections.emptyList(), actualRR.getRelatedRangesList()); - assertEquals(expectedRangeMetadata.getProps(), actualRR.getProps()); - } - - } - - private void verifyStreamMetadata(MetaRangeImpl metaRange, - StreamProperties streamProps) - throws Exception { - // verify the stream properties - assertEquals( - LifecycleState.CREATED, - metaRange.unsafeGetLifecycleState()); - assertEquals( - name.getMethodName() + "_stream", - metaRange.getName()); - long cTime = metaRange.unsafeGetCreationTime(); - assertEquals(streamProps, metaRange.unsafeGetStreamProperties()); - assertEquals(streamProps.getStreamId(), metaRange.unsafeGetStreamId()); - assertEquals(ServingState.WRITABLE, FutureUtils.result(metaRange.getServingState())); - assertEquals( - streamProps.getStreamConf(), - FutureUtils.result(metaRange.getConfiguration())); - - // verify the stream ranges - List activeRanges = Lists.transform( - FutureUtils.result(metaRange.getActiveRanges()), - (metadata) -> metadata.getProps().getRangeId() - ); - assertEquals(streamProps.getStreamConf().getInitialNumRanges(), activeRanges.size()); - assertEquals( - Lists.newArrayList(LongStream.range(1024L, 1024L + activeRanges.size()).iterator()), - activeRanges); - NavigableMap ranges = metaRange.unsafeGetRanges(); - long startKey = Long.MIN_VALUE; - long rangeSize = Long.MAX_VALUE / (activeRanges.size() / 2); - for (int idx = 0; idx < activeRanges.size(); ++idx) { - long rid = activeRanges.get(idx); - RangeMetadata rangeMetadata = ranges.get(rid); - long endKey = startKey + rangeSize; - if (idx == activeRanges.size() - 1) { - endKey = Long.MAX_VALUE; - } - - verifyRangeMetadata(rangeMetadata, - startKey, - endKey, - rid, - cTime, - Long.MAX_VALUE, - RangeState.RANGE_ACTIVE); - - readRangeMetadataAndVerify(streamProps.getStreamId(), rid, - startKey, - endKey, - rid, - cTime, - Long.MAX_VALUE, - RangeState.RANGE_ACTIVE); - - startKey = endKey; - } - } - - private void readRangeMetadataAndVerify(long streamId, - long rangeId, - long expectedStartKey, - long expectedEndKey, - long expectedRid, - long expectedCTime, - long expectedFenceTime, - RangeState expectedRangeState) throws Exception { - byte[] rangeKey = MetaRangeImpl.getStreamRangeKey(streamId, rangeId); - byte[] rangeMetadataBytes = FutureUtils.result(store.get(rangeKey)); - RangeMetadata rangeMetadata = RangeMetadata.parseFrom(rangeMetadataBytes); - - verifyRangeMetadata( - rangeMetadata, - expectedStartKey, - expectedEndKey, - expectedRid, - expectedCTime, - expectedFenceTime, - expectedRangeState); - } - - private void verifyRangeMetadata(RangeMetadata metadata, - long expectedStartKey, - long expectedEndKey, - long expectedRid, - long expectedCTime, - long expectedFenceTime, - RangeState expectedRangeState) { - assertEquals(expectedStartKey, metadata.getProps().getStartHashKey()); - assertEquals(expectedEndKey, metadata.getProps().getEndHashKey()); - assertEquals(expectedRid, metadata.getProps().getRangeId()); - assertEquals(expectedCTime, metadata.getCreateTime()); - assertEquals(expectedFenceTime, metadata.getFenceTime()); - assertEquals(expectedRangeState, metadata.getState()); - } - - @Test - public void testGetTwice() throws Exception { - GetActiveRangesResponse resp = FutureUtils.result( - this.mrStoreImpl.getActiveRanges(createRequest(streamProps))); - - assertEquals(StatusCode.SUCCESS, resp.getCode()); - - verifyGetResponse(resp); - - GetActiveRangesResponse secondResp = FutureUtils.result( - this.mrStoreImpl.getActiveRanges(createRequest(streamProps))); - - assertEquals(StatusCode.SUCCESS, secondResp.getCode()); - - verifyGetResponse(secondResp); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java deleted file mode 100644 index 9cdbf6424df..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.metadata; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.MIN_DATA_STREAM_ID; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateStreamRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteStreamRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetNamespaceRequest; -import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetStreamRequest; -import static org.apache.bookkeeper.stream.storage.impl.metadata.RootRangeStoreImpl.NS_ID_KEY; -import static org.apache.bookkeeper.stream.storage.impl.metadata.RootRangeStoreImpl.STREAM_ID_KEY; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.CompletableFuture; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.Bytes; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerPlacementPolicyImpl; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCAsyncStoreTestBase; -import org.junit.Test; - -/** - * Unit test for {@link RootRangeStoreImpl}. - */ -@Slf4j -public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase { - - private final NamespaceConfiguration namespaceConf = - NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - - private final StreamConfiguration streamConf = - StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .build(); - - - private RootRangeStoreImpl rootRangeStore; - - @Override - protected void doSetup() throws Exception { - rootRangeStore = new RootRangeStoreImpl( - store, - StorageContainerPlacementPolicyImpl.of(1024), - scheduler.chooseThread()); - } - - @Override - protected void doTeardown() throws Exception { - if (null != store) { - store.close(); - } - } - - // - // Tests for Namespace API - // - - private void verifyNamespaceExists(String nsName, long nsId) throws Exception { - assertNotNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getNamespaceIdKey(nsId)))); - assertNotNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getNamespaceNameKey(nsName)))); - } - - private void verifyNamespaceNotExists(String nsName, long nsId) throws Exception { - assertNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getNamespaceIdKey(nsId)))); - assertNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getNamespaceNameKey(nsName)))); - } - - private void verifyNamespaceId(long nsId) throws Exception { - byte[] nsIdKey = FutureUtils.result(store.get(NS_ID_KEY)); - if (nsId < 0) { - assertNull(nsIdKey); - } else { - assertNotNull(nsIdKey); - assertEquals(nsId, Bytes.toLong(nsIdKey, 0)); - } - } - - private void verifyStreamId(long streamId) throws Exception { - byte[] streamIdKey = FutureUtils.result(store.get(STREAM_ID_KEY)); - if (streamId < 0) { - assertNull(streamIdKey); - } else { - assertNotNull(streamIdKey); - assertEquals(streamId, Bytes.toLong(streamIdKey, 0)); - } - } - - private CreateNamespaceResponse createNamespaceAndVerify(String nsName, long expectedNsId) - throws Exception { - CompletableFuture createFuture = rootRangeStore.createNamespace( - createCreateNamespaceRequest(nsName, namespaceConf)); - CreateNamespaceResponse response = FutureUtils.result(createFuture); - assertEquals(StatusCode.SUCCESS, response.getCode()); - assertEquals(expectedNsId, response.getNsProps().getNamespaceId()); - assertEquals(nsName, response.getNsProps().getNamespaceName()); - assertEquals(namespaceConf.getDefaultStreamConf(), response.getNsProps().getDefaultStreamConf()); - - return response; - } - - private void getNamespaceAndVerify(String nsName, - long expectedNsId, - StreamConfiguration streamConf) throws Exception { - CompletableFuture getFuture = rootRangeStore.getNamespace( - createGetNamespaceRequest(nsName)); - GetNamespaceResponse getResp = FutureUtils.result(getFuture); - assertEquals(expectedNsId, getResp.getNsProps().getNamespaceId()); - assertEquals(streamConf, getResp.getNsProps().getDefaultStreamConf()); - } - - @Test - public void testCreateNamespaceInvalidName() throws Exception { - String nsName = ""; - CompletableFuture createFuture = rootRangeStore.createNamespace( - createCreateNamespaceRequest(nsName, namespaceConf)); - CreateNamespaceResponse response = FutureUtils.result(createFuture); - assertEquals(StatusCode.INVALID_NAMESPACE_NAME, response.getCode()); - - verifyNamespaceId(-1); - } - - @Test - public void testCreateNamespaceSuccess() throws Exception { - String nsName = name.getMethodName(); - - CreateNamespaceResponse response = createNamespaceAndVerify(nsName, 0L); - - verifyNamespaceExists(nsName, response.getNsProps().getNamespaceId()); - verifyNamespaceId(0L); - } - - @Test - public void testCreateNamespaceExists() throws Exception { - String nsName = name.getMethodName(); - - // create first namespace - CreateNamespaceResponse response = createNamespaceAndVerify(nsName, 0L); - verifyNamespaceExists(nsName, response.getNsProps().getNamespaceId()); - verifyNamespaceId(0L); - - // create the namespace with same name will fail - CreateNamespaceResponse response2 = FutureUtils.result( - rootRangeStore.createNamespace( - createCreateNamespaceRequest(nsName, namespaceConf))); - assertEquals(StatusCode.INTERNAL_SERVER_ERROR, response2.getCode()); - - // namespace will not be advanced - verifyNamespaceId(0L); - } - - @Test - public void testDeleteNamespaceInvalidName() throws Exception { - String nsName = ""; - CompletableFuture deleteFuture = rootRangeStore.deleteNamespace( - createDeleteNamespaceRequest(nsName)); - DeleteNamespaceResponse response = FutureUtils.result(deleteFuture); - assertEquals(StatusCode.INVALID_NAMESPACE_NAME, response.getCode()); - } - - private DeleteNamespaceResponse deleteNamespaceAndVerify(String nsName) throws Exception { - CompletableFuture deleteFuture = rootRangeStore.deleteNamespace( - createDeleteNamespaceRequest(nsName)); - DeleteNamespaceResponse deleteResp = FutureUtils.result(deleteFuture); - assertEquals(StatusCode.SUCCESS, deleteResp.getCode()); - return deleteResp; - } - - @Test - public void testDeleteNamespaceSuccess() throws Exception { - String nsName = name.getMethodName(); - - CreateNamespaceResponse createResp = createNamespaceAndVerify(nsName, 0L); - verifyNamespaceExists(nsName, createResp.getNsProps().getNamespaceId()); - verifyNamespaceId(0L); - - deleteNamespaceAndVerify(nsName); - verifyNamespaceNotExists(nsName, createResp.getNsProps().getNamespaceId()); - verifyNamespaceId(0L); - } - - @Test - public void testDeleteNamespaceNotFound() throws Exception { - String nsName = name.getMethodName(); - CompletableFuture deleteFuture = rootRangeStore.deleteNamespace( - createDeleteNamespaceRequest(nsName)); - // create first namespace - DeleteNamespaceResponse response = FutureUtils.result(deleteFuture); - assertEquals(StatusCode.NAMESPACE_NOT_FOUND, response.getCode()); - - verifyNamespaceNotExists(nsName, 0L); - verifyNamespaceId(-1L); - } - - @Test - public void testGetNamespaceInvalidName() throws Exception { - String nsName = ""; - CompletableFuture getFuture = rootRangeStore.getNamespace( - createGetNamespaceRequest(nsName)); - GetNamespaceResponse response = FutureUtils.result(getFuture); - assertEquals(StatusCode.INVALID_NAMESPACE_NAME, response.getCode()); - } - - @Test - public void testGetNamespaceNotFound() throws Exception { - String nsName = name.getMethodName(); - CompletableFuture getFuture = rootRangeStore.getNamespace( - createGetNamespaceRequest(nsName)); - // create first namespace - GetNamespaceResponse response = FutureUtils.result(getFuture); - assertEquals(StatusCode.NAMESPACE_NOT_FOUND, response.getCode()); - - verifyNamespaceNotExists(nsName, 0L); - verifyNamespaceId(-1L); - } - - @Test - public void testGetNamespaceSuccess() throws Exception { - String nsName = name.getMethodName(); - - CreateNamespaceResponse response = createNamespaceAndVerify(nsName, 0L); - getNamespaceAndVerify(nsName, 0L, namespaceConf.getDefaultStreamConf()); - - verifyNamespaceId(0); - } - - // - // Tests for Stream API - // - - @Test - public void testCreateStreamInvalidName() throws Exception { - String nsName = name.getMethodName(); - String streamName = ""; - CompletableFuture createFuture = rootRangeStore.createStream( - createCreateStreamRequest(nsName, streamName, streamConf)); - CreateStreamResponse response = FutureUtils.result(createFuture); - assertEquals(StatusCode.INVALID_STREAM_NAME, response.getCode()); - } - - @Test - public void testCreateStreamNamespaceNotFound() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - CompletableFuture createFuture = rootRangeStore.createStream( - createCreateStreamRequest(nsName, streamName, streamConf)); - CreateStreamResponse response = FutureUtils.result(createFuture); - assertEquals(StatusCode.NAMESPACE_NOT_FOUND, response.getCode()); - } - - private CreateStreamResponse createStreamAndVerify(String nsName, - String streamName, - long expectedStreamId) throws Exception { - CompletableFuture createFuture = rootRangeStore.createStream( - createCreateStreamRequest(nsName, streamName, streamConf)); - CreateStreamResponse response = FutureUtils.result(createFuture); - assertEquals(StatusCode.SUCCESS, response.getCode()); - assertEquals(MIN_DATA_STREAM_ID, response.getStreamProps().getStreamId()); - assertEquals(streamName, response.getStreamProps().getStreamName()); - assertEquals(streamConf, response.getStreamProps().getStreamConf()); - assertTrue(response.getStreamProps().getStorageContainerId() >= 0); - return response; - } - - private void verifyStreamExists(long nsId, String streamName, long streamId) throws Exception { - assertNotNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getStreamNameKey(nsId, streamName)))); - assertNotNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getStreamIdKey(nsId, streamId)))); - } - - private void verifyStreamNotExists(long nsId, String streamName, long streamId) throws Exception { - assertNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getStreamNameKey(nsId, streamName)))); - assertNull( - FutureUtils.result( - store.get(RootRangeStoreImpl.getStreamIdKey(nsId, streamId)))); - } - - @Test - public void testCreateStreamSuccess() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - - CreateNamespaceResponse createResp = createNamespaceAndVerify(nsName, 0L); - createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID); - - verifyStreamExists( - createResp.getNsProps().getNamespaceId(), - streamName, - MIN_DATA_STREAM_ID); - verifyStreamId(MIN_DATA_STREAM_ID); - } - - @Test - public void testCreateStreamExists() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - - CreateNamespaceResponse createResp = createNamespaceAndVerify(nsName, 0L); - createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID); - - verifyStreamExists( - createResp.getNsProps().getNamespaceId(), - streamName, - MIN_DATA_STREAM_ID); - verifyStreamId(MIN_DATA_STREAM_ID); - - // create the namespace with same name will fail - CreateStreamResponse response2 = FutureUtils.result( - rootRangeStore.createStream( - createCreateStreamRequest(nsName, streamName, streamConf))); - // TODO: change it later - assertEquals(StatusCode.INTERNAL_SERVER_ERROR, response2.getCode()); - - verifyStreamId(MIN_DATA_STREAM_ID); - } - - @Test - public void testDeleteStreamInvalidName() throws Exception { - String nsName = name.getMethodName(); - String streamName = ""; - CompletableFuture deleteFuture = rootRangeStore.deleteStream( - createDeleteStreamRequest(nsName, streamName)); - DeleteStreamResponse response = FutureUtils.result(deleteFuture); - assertEquals(StatusCode.INVALID_STREAM_NAME, response.getCode()); - } - - @Test - public void testDeleteStreamNamespaceNotFound() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - CompletableFuture deleteFuture = rootRangeStore.deleteStream( - createDeleteStreamRequest(nsName, streamName)); - DeleteStreamResponse response = FutureUtils.result(deleteFuture); - assertEquals(StatusCode.NAMESPACE_NOT_FOUND, response.getCode()); - } - - @Test - public void testDeleteStreamSuccess() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - - CreateNamespaceResponse createResp = createNamespaceAndVerify(nsName, 0L); - createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID); - - verifyStreamExists( - createResp.getNsProps().getNamespaceId(), - streamName, - MIN_DATA_STREAM_ID); - verifyStreamId(MIN_DATA_STREAM_ID); - - CompletableFuture deleteFuture = rootRangeStore.deleteStream( - createDeleteStreamRequest(nsName, streamName)); - DeleteStreamResponse deleteResp = FutureUtils.result(deleteFuture); - assertEquals(StatusCode.SUCCESS, deleteResp.getCode()); - - verifyStreamNotExists( - createResp.getNsProps().getNamespaceId(), - streamName, - MIN_DATA_STREAM_ID); - verifyStreamId(MIN_DATA_STREAM_ID); - } - - @Test - public void testDeleteStreamNotFound() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - - createNamespaceAndVerify(nsName, 0L); - - CompletableFuture deleteFuture = rootRangeStore.deleteStream( - createDeleteStreamRequest(nsName, streamName)); - DeleteStreamResponse response = FutureUtils.result(deleteFuture); - assertEquals(StatusCode.STREAM_NOT_FOUND, response.getCode()); - - verifyStreamId(-1L); - } - - @Test - public void testGetStreamInvalidName() throws Exception { - String nsName = name.getMethodName(); - String streamName = ""; - CompletableFuture getFuture = rootRangeStore.getStream( - createGetStreamRequest(nsName, streamName)); - GetStreamResponse response = FutureUtils.result(getFuture); - assertEquals(StatusCode.INVALID_STREAM_NAME, response.getCode()); - } - - @Test - public void testGetStreamNamespaceNotFound() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - CompletableFuture getFuture = rootRangeStore.getStream( - createGetStreamRequest(nsName, streamName)); - GetStreamResponse response = FutureUtils.result(getFuture); - assertEquals(StatusCode.NAMESPACE_NOT_FOUND, response.getCode()); - } - - @Test - public void testGetStreamSuccess() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - - createNamespaceAndVerify(nsName, 0L); - createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID); - verifyStreamId(MIN_DATA_STREAM_ID); - - CompletableFuture getFuture = rootRangeStore.getStream( - createGetStreamRequest(nsName, streamName)); - GetStreamResponse getResp = FutureUtils.result(getFuture); - assertEquals(StatusCode.SUCCESS, getResp.getCode()); - assertEquals(MIN_DATA_STREAM_ID, getResp.getStreamProps().getStreamId()); - assertEquals(streamName, getResp.getStreamProps().getStreamName()); - assertEquals(streamConf, getResp.getStreamProps().getStreamConf()); - } - - @Test - public void testGetStreamByIdSuccess() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - - createNamespaceAndVerify(nsName, 0L); - createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID); - verifyStreamId(MIN_DATA_STREAM_ID); - - CompletableFuture getFuture = rootRangeStore.getStream( - createGetStreamRequest(MIN_DATA_STREAM_ID)); - GetStreamResponse getResp = FutureUtils.result(getFuture); - assertEquals(StatusCode.SUCCESS, getResp.getCode()); - assertEquals(MIN_DATA_STREAM_ID, getResp.getStreamProps().getStreamId()); - assertEquals(streamName, getResp.getStreamProps().getStreamName()); - assertEquals(streamConf, getResp.getStreamProps().getStreamConf()); - } - - @Test - public void testGetStreamNotFound() throws Exception { - String nsName = name.getMethodName(); - String streamName = name.getMethodName(); - - createNamespaceAndVerify(nsName, 0L); - - verifyStreamId(-1); - - CompletableFuture getFuture = rootRangeStore.getStream( - createGetStreamRequest(nsName, streamName)); - GetStreamResponse response = FutureUtils.result(getFuture); - assertEquals(StatusCode.STREAM_NOT_FOUND, response.getCode()); - } - - @Test - public void testGetStreamByIdNotFound() throws Exception { - String nsName = name.getMethodName(); - - createNamespaceAndVerify(nsName, 0L); - - verifyStreamId(-1); - - CompletableFuture getFuture = rootRangeStore.getStream( - createGetStreamRequest(MIN_DATA_STREAM_ID)); - GetStreamResponse response = FutureUtils.result(getFuture); - assertEquals(StatusCode.STREAM_NOT_FOUND, response.getCode()); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/stream/TestMetaRangeImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/stream/TestMetaRangeImpl.java deleted file mode 100644 index 62982e14ca3..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/stream/TestMetaRangeImpl.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.metadata.stream; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.NavigableMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.stream.LongStream; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.RangeMetadata; -import org.apache.bookkeeper.stream.proto.RangeState; -import org.apache.bookkeeper.stream.proto.StreamMetadata.LifecycleState; -import org.apache.bookkeeper.stream.proto.StreamMetadata.ServingState; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerPlacementPolicyImpl; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCAsyncStoreTestBase; -import org.junit.Test; - -/** - * Unit test of {@link MetaRangeImpl}. - */ -@Slf4j -public class TestMetaRangeImpl extends MVCCAsyncStoreTestBase { - - private StreamProperties streamProps; - private MetaRangeImpl metaRange; - - @Override - protected void doSetup() { - this.streamProps = StreamProperties.newBuilder() - .setStorageContainerId(1234L) - .setStreamConf(DEFAULT_STREAM_CONF) - .setStreamName(name.getMethodName() + "_stream") - .setStreamId(System.currentTimeMillis()) - .build(); - this.metaRange = new MetaRangeImpl( - this.store, - this.scheduler.chooseThread(), - StorageContainerPlacementPolicyImpl.of(1024)); - } - - @Override - protected void doTeardown() throws Exception { - } - - private void assertIllegalStateException(CompletableFuture future) throws Exception { - try { - future.get(); - fail("Should fail on illegal state"); - } catch (ExecutionException ee) { - // expected. - assertTrue(ee.getCause() instanceof IllegalStateException); - } - } - - @Test - public void testCreate() throws Exception { - assertTrue(FutureUtils.result(this.metaRange.create(streamProps))); - - verifyStreamMetadata(metaRange, streamProps); - } - - @Test - public void testLoad() throws Exception { - assertTrue(FutureUtils.result(this.metaRange.create(streamProps))); - - MetaRangeImpl newMetaRange = new MetaRangeImpl( - store, - scheduler.chooseThread(), - StorageContainerPlacementPolicyImpl.of(1024)); - assertNotNull(FutureUtils.result(newMetaRange.load(streamProps.getStreamId()))); - verifyStreamMetadata(newMetaRange, streamProps); - } - - private void verifyStreamMetadata(MetaRangeImpl metaRange, - StreamProperties streamProps) - throws Exception { - // verify the stream properties - assertEquals( - LifecycleState.CREATED, - metaRange.unsafeGetLifecycleState()); - assertEquals( - name.getMethodName() + "_stream", - this.metaRange.getName()); - long cTime = metaRange.unsafeGetCreationTime(); - assertTrue(metaRange.unsafeGetCreationTime() == this.metaRange.unsafeGetModificationTime()); - assertEquals(streamProps, metaRange.unsafeGetStreamProperties()); - assertEquals(streamProps.getStreamId(), metaRange.unsafeGetStreamId()); - assertEquals(ServingState.WRITABLE, FutureUtils.result(metaRange.getServingState())); - assertEquals( - streamProps.getStreamConf(), - FutureUtils.result(metaRange.getConfiguration())); - - // verify the stream ranges - List activeRanges = Lists.transform( - FutureUtils.result(metaRange.getActiveRanges()), - (metadata) -> metadata.getProps().getRangeId() - ); - assertEquals(streamProps.getStreamConf().getInitialNumRanges(), activeRanges.size()); - assertEquals( - Lists.newArrayList(LongStream.range(1024L, 1024L + activeRanges.size()).iterator()), - activeRanges); - NavigableMap ranges = metaRange.unsafeGetRanges(); - long startKey = Long.MIN_VALUE; - long rangeSize = Long.MAX_VALUE / (activeRanges.size() / 2); - for (int idx = 0; idx < activeRanges.size(); ++idx) { - long rid = activeRanges.get(idx); - RangeMetadata rangeMetadata = ranges.get(rid); - long endKey = startKey + rangeSize; - if (idx == activeRanges.size() - 1) { - endKey = Long.MAX_VALUE; - } - - verifyRangeMetadata(rangeMetadata, - startKey, - endKey, - rid, - cTime, - Long.MAX_VALUE, - RangeState.RANGE_ACTIVE); - - readRangeMetadataAndVerify(streamProps.getStreamId(), rid, - startKey, - endKey, - rid, - cTime, - Long.MAX_VALUE, - RangeState.RANGE_ACTIVE); - - startKey = endKey; - } - } - - private void readRangeMetadataAndVerify(long streamId, - long rangeId, - long expectedStartKey, - long expectedEndKey, - long expectedRid, - long expectedCTime, - long expectedFenceTime, - RangeState expectedRangeState) throws Exception { - byte[] rangeKey = MetaRangeImpl.getStreamRangeKey(streamId, rangeId); - byte[] rangeMetadataBytes = FutureUtils.result(store.get(rangeKey)); - RangeMetadata rangeMetadata = RangeMetadata.parseFrom(rangeMetadataBytes); - - verifyRangeMetadata( - rangeMetadata, - expectedStartKey, - expectedEndKey, - expectedRid, - expectedCTime, - expectedFenceTime, - expectedRangeState); - } - - private void verifyRangeMetadata(RangeMetadata metadata, - long expectedStartKey, - long expectedEndKey, - long expectedRid, - long expectedCTime, - long expectedFenceTime, - RangeState expectedRangeState) { - assertEquals(expectedStartKey, metadata.getProps().getStartHashKey()); - assertEquals(expectedEndKey, metadata.getProps().getEndHashKey()); - assertEquals(expectedRid, metadata.getProps().getRangeId()); - assertEquals(expectedCTime, metadata.getCreateTime()); - assertEquals(expectedFenceTime, metadata.getFenceTime()); - assertEquals(expectedRangeState, metadata.getState()); - } - - @Test - public void testDoubleCreate() throws Exception { - // create first time - assertTrue(FutureUtils.result(this.metaRange.create(streamProps))); - // created again - assertIllegalStateException(this.metaRange.create(streamProps)); - } - - @Test - public void testUpdateServingState() throws Exception { - // create first time - assertTrue(FutureUtils.result(this.metaRange.create(streamProps))); - long mTime = this.metaRange.unsafeGetModificationTime(); - assertEquals( - ServingState.WRITABLE, - FutureUtils.result(this.metaRange.getServingState())); - long newTime = this.metaRange.unsafeGetModificationTime(); - assertTrue(newTime >= mTime); - mTime = newTime; - assertEquals( - ServingState.READONLY, - FutureUtils.result(this.metaRange.updateServingState(ServingState.READONLY))); - newTime = this.metaRange.unsafeGetModificationTime(); - assertTrue(newTime >= mTime); - } - - @Test - public void testUpdateServingStateConcurrently() throws Exception { - assertTrue(FutureUtils.result(this.metaRange.create(streamProps))); - - long mTime = this.metaRange.unsafeGetModificationTime(); - - CompletableFuture updateFuture1 = metaRange.updateServingState(ServingState.WRITABLE); - CompletableFuture updateFuture2 = metaRange.updateServingState(ServingState.READONLY); - - try { - updateFuture1.get(); - } catch (Exception e) { - assertEquals(ServingState.READONLY, updateFuture2.get()); - assertTrue(metaRange.unsafeGetModificationTime() >= mTime); - assertEquals(ServingState.READONLY, FutureUtils.result(this.metaRange.getServingState())); - } - try { - updateFuture2.get(); - } catch (Exception e) { - assertEquals(ServingState.WRITABLE, updateFuture1.get()); - assertTrue(metaRange.unsafeGetModificationTime() >= mTime); - assertEquals(ServingState.WRITABLE, FutureUtils.result(this.metaRange.getServingState())); - } - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RangeRoutingTableImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RangeRoutingTableImplTest.java deleted file mode 100644 index 8201ba714d7..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RangeRoutingTableImplTest.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.routing; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import io.grpc.stub.StreamObserver; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.internal.ProtocolInternalUtils; -import org.apache.bookkeeper.clients.impl.routing.RangeRouter; -import org.apache.bookkeeper.common.router.BytesHashRouter; -import org.apache.bookkeeper.stream.proto.RangeProperties; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse; -import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.RelatedRanges; -import org.apache.bookkeeper.stream.proto.storage.RelationType; -import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceImplBase; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.protocol.util.ProtoUtils; -import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerPlacementPolicyImpl; -import org.junit.Test; - -/** - * Unit test {@link RangeRoutingTable}. - */ -public class RangeRoutingTableImplTest extends GrpcClientTestBase { - - private final long scId = 1234L; - private final long streamId = 123456L; - private GetActiveRangesResponse getActiveRangesResponse; - private CompletableFuture responseSupplier; - private StreamProperties props; - private List rangeProps; - private RangeRoutingTableImpl routingTable; - private RangeRouter rangeRouter; - - @Override - protected void doSetup() throws Exception { - this.props = StreamProperties.newBuilder() - .setStorageContainerId(scId) - .setStreamId(streamId) - .setStreamName("metaclient-stream") - .setStreamConf(StreamConfiguration.newBuilder().build()) - .build(); - this.rangeProps = ProtoUtils.split( - streamId, - 24, - 23456L, - StorageContainerPlacementPolicyImpl.of(4) - ); - final GetActiveRangesResponse.Builder getActiveRangesResponseBuilder = GetActiveRangesResponse.newBuilder(); - for (RangeProperties range : rangeProps) { - RelatedRanges.Builder rrBuilder = RelatedRanges.newBuilder() - .setProps(range) - .setType(RelationType.PARENTS) - .addAllRelatedRanges(Collections.emptyList()); - getActiveRangesResponseBuilder.addRanges(rrBuilder); - } - this.getActiveRangesResponse = getActiveRangesResponseBuilder - .setCode(StatusCode.SUCCESS) - .build(); - RootRangeServiceImplBase rootRangeService = new RootRangeServiceImplBase() { - @Override - public void getStream(GetStreamRequest request, - StreamObserver responseObserver) { - responseObserver.onNext(GetStreamResponse.newBuilder() - .setCode(StatusCode.SUCCESS) - .setStreamProps(props) - .build()); - responseObserver.onCompleted(); - } - }; - serviceRegistry.addService(rootRangeService); - - this.responseSupplier = new CompletableFuture<>(); - // register a good meta range service - MetaRangeServiceImplBase metaRangeService = new MetaRangeServiceImplBase() { - @Override - public void getActiveRanges(GetActiveRangesRequest request, - StreamObserver responseObserver) { - try { - responseObserver.onNext(responseSupplier.get()); - responseObserver.onCompleted(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - responseObserver.onError(e); - } catch (ExecutionException e) { - responseObserver.onError(e); - } - } - }; - serviceRegistry.addService(metaRangeService); - - this.routingTable = new RangeRoutingTableImpl(serverManager); - this.rangeRouter = new RangeRouter<>(BytesHashRouter.of()); - this.rangeRouter.setRanges(ProtocolInternalUtils.createActiveRanges(getActiveRangesResponse)); - } - - @Override - protected void doTeardown() throws Exception { - } - - @Test - public void testGetRange() throws Exception { - String key = "foo"; - byte[] keyBytes = key.getBytes(UTF_8); - RangeProperties rangeProps = routingTable.getRange(streamId, keyBytes); - // the first get will return null since there is nothing in - assertNull(rangeProps); - // the fetch request is outstanding - CompletableFuture> outstandingFetchFuture = - routingTable.getOutstandingFetchRequest(streamId); - assertNotNull(outstandingFetchFuture); - assertFalse(outstandingFetchFuture.isDone()); - - // complete the response supplier, so the fetch request can complete to update the cache - responseSupplier.complete(getActiveRangesResponse); - - // wait until the stuff is cached. - while (null == routingTable.getRangeRouter(streamId)) { - TimeUnit.MILLISECONDS.sleep(100); - } - - // if the router is created, it should return the cached router - rangeProps = routingTable.getRange(streamId, keyBytes); - assertNotNull(rangeProps); - assertEquals(rangeRouter.getRangeProperties(keyBytes), rangeProps); - } - - @Test - public void testGetRangeException() throws Exception { - String key = "foo"; - byte[] keyBytes = key.getBytes(UTF_8); - RangeProperties rangeProps = routingTable.getRange(streamId, keyBytes); - // the first get will return null since there is nothing in - assertNull(rangeProps); - // the fetch request is outstanding - CompletableFuture> outstandingFetchFuture = - routingTable.getOutstandingFetchRequest(streamId); - assertNotNull(outstandingFetchFuture); - assertFalse(outstandingFetchFuture.isDone()); - - // complete the response supplier, so the fetch request can complete to update the cache - responseSupplier.completeExceptionally(new Exception("fetch failed")); - - // wait until the fetch is done. - try { - outstandingFetchFuture.get(); - fail("Fetch request should fail"); - } catch (Exception e) { - // expected - } - - // once the fetch is done, nothing should be cached and the outstanding fetch request should be removed - assertNull(routingTable.getRangeRouter(streamId)); - assertNull(routingTable.getOutstandingFetchRequest(streamId)); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RoutingHeaderProxyInterceptorTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RoutingHeaderProxyInterceptorTest.java deleted file mode 100644 index 43c060b12ca..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/RoutingHeaderProxyInterceptorTest.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.routing; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.RID_METADATA_KEY; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.RK_METADATA_KEY; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.SID_METADATA_KEY; -import static org.junit.Assert.assertEquals; - -import com.google.protobuf.ByteString; -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.ClientCall; -import io.grpc.ClientInterceptor; -import io.grpc.ClientInterceptors.CheckedForwardingClientCall; -import io.grpc.Metadata; -import io.grpc.MethodDescriptor; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Test; - -/** - * Unit test {@link RoutingHeaderProxyInterceptor}. - */ -@Slf4j -public class RoutingHeaderProxyInterceptorTest extends GrpcClientTestBase { - - private final long streamId = 1234L; - private final long rangeId = 2345L; - private final byte[] routingKey = ("routing-key-" + System.currentTimeMillis()).getBytes(UTF_8); - private final AtomicReference receivedRequest = new AtomicReference<>(); - private StorageServerChannel channel; - - @Override - protected void doSetup() { - TableServiceImplBase tableService = new TableServiceImplBase() { - - @Override - public void range(RangeRequest request, StreamObserver responseObserver) { - log.info("Received range request : {}", request); - receivedRequest.set(request); - responseObserver.onNext(RangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(request.getHeader()) - .build()) - .build()); - responseObserver.onCompleted(); - } - - @Override - public void delete(DeleteRangeRequest request, StreamObserver responseObserver) { - log.info("Received delete range request : {}", request); - receivedRequest.set(request); - responseObserver.onNext(DeleteRangeResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(request.getHeader()) - .build()) - .build()); - responseObserver.onCompleted(); - } - - @Override - public void txn(TxnRequest request, StreamObserver responseObserver) { - log.info("Received txn request : {}", request); - receivedRequest.set(request); - responseObserver.onNext(TxnResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(request.getHeader()) - .build()) - .build()); - responseObserver.onCompleted(); - } - - @Override - public void increment(IncrementRequest request, StreamObserver responseObserver) { - log.info("Received incr request : {}", request); - receivedRequest.set(request); - responseObserver.onNext(IncrementResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(request.getHeader()) - .build()) - .build()); - responseObserver.onCompleted(); - } - - @Override - public void put(PutRequest request, StreamObserver responseObserver) { - log.info("Received put request : {}", request); - receivedRequest.set(request); - responseObserver.onNext(PutResponse.newBuilder() - .setHeader(ResponseHeader.newBuilder() - .setCode(StatusCode.SUCCESS) - .setRoutingHeader(request.getHeader()) - .build()) - .build()); - responseObserver.onCompleted(); - } - }; - serviceRegistry.addService(tableService.bindService()); - - - this.channel = new StorageServerChannel( - InProcessChannelBuilder.forName(serverName).directExecutor().build(), - Optional.empty() - ).intercept( - new RoutingHeaderProxyInterceptor(), - new ClientInterceptor() { - @Override - public ClientCall interceptCall(MethodDescriptor method, - CallOptions callOptions, - Channel next) { - return new CheckedForwardingClientCall(next.newCall(method, callOptions)) { - @Override - protected void checkedStart(Listener responseListener, Metadata headers) { - log.info("Intercept the request with routing information : sid = {}, rid = {}, rk = {}", - streamId, rangeId, new String(routingKey, UTF_8)); - headers.put( - RID_METADATA_KEY, - rangeId - ); - headers.put( - SID_METADATA_KEY, - streamId - ); - headers.put( - RK_METADATA_KEY, - routingKey - ); - delegate().start(responseListener, headers); - } - }; - } - } - ); - } - - @Override - protected void doTeardown() { - channel.close(); - } - - @Test - public void testPutRequest() throws Exception { - PutRequest request = PutRequest.newBuilder() - .setKey(ByteString.copyFromUtf8("test-key")) - .build(); - PutRequest expectedRequest = PutRequest.newBuilder(request) - .setHeader(RoutingHeader.newBuilder(request.getHeader()) - .setStreamId(streamId) - .setRangeId(rangeId) - .setRKey(ByteString.copyFrom(routingKey)) - .build()) - .build(); - PutResponse response = this.channel.getTableService().put(request).get(); - - assertEquals(expectedRequest, receivedRequest.get()); - assertEquals(expectedRequest.getHeader(), response.getHeader().getRoutingHeader()); - } - - @Test - public void testRangeRequest() throws Exception { - RangeRequest request = RangeRequest.newBuilder() - .setKey(ByteString.copyFromUtf8("test-key")) - .build(); - RangeRequest expectedRequest = RangeRequest.newBuilder(request) - .setHeader(RoutingHeader.newBuilder(request.getHeader()) - .setStreamId(streamId) - .setRangeId(rangeId) - .setRKey(ByteString.copyFrom(routingKey)) - .build()) - .build(); - RangeResponse response = this.channel.getTableService() - .range(request).get(); - - assertEquals(expectedRequest, receivedRequest.get()); - assertEquals(expectedRequest.getHeader(), response.getHeader().getRoutingHeader()); - } - - @Test - public void testDeleteRangeRequest() throws Exception { - DeleteRangeRequest request = DeleteRangeRequest.newBuilder() - .setKey(ByteString.copyFromUtf8("test-key")) - .build(); - DeleteRangeRequest expectedRequest = DeleteRangeRequest.newBuilder(request) - .setHeader(RoutingHeader.newBuilder(request.getHeader()) - .setStreamId(streamId) - .setRangeId(rangeId) - .setRKey(ByteString.copyFrom(routingKey)) - .build()) - .build(); - DeleteRangeResponse response = this.channel.getTableService() - .delete(request).get(); - - assertEquals(expectedRequest, receivedRequest.get()); - assertEquals(expectedRequest.getHeader(), response.getHeader().getRoutingHeader()); - } - - @Test - public void testIncrementRequest() throws Exception { - IncrementRequest request = IncrementRequest.newBuilder() - .setKey(ByteString.copyFromUtf8("test-key")) - .build(); - IncrementRequest expectedRequest = IncrementRequest.newBuilder(request) - .setHeader(RoutingHeader.newBuilder(request.getHeader()) - .setStreamId(streamId) - .setRangeId(rangeId) - .setRKey(ByteString.copyFrom(routingKey)) - .build()) - .build(); - IncrementResponse response = this.channel.getTableService() - .increment(request).get(); - - assertEquals(expectedRequest, receivedRequest.get()); - assertEquals(expectedRequest.getHeader(), response.getHeader().getRoutingHeader()); - } - - @Test - public void testTxnRequest() throws Exception { - TxnRequest request = TxnRequest.newBuilder() - .build(); - TxnRequest expectedRequest = TxnRequest.newBuilder(request) - .setHeader(RoutingHeader.newBuilder(request.getHeader()) - .setStreamId(streamId) - .setRangeId(rangeId) - .setRKey(ByteString.copyFrom(routingKey)) - .build()) - .build(); - TxnResponse response = this.channel.getTableService().txn(request).get(); - - assertEquals(expectedRequest, receivedRequest.get()); - assertEquals(expectedRequest.getHeader(), response.getHeader().getRoutingHeader()); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/StorageContainerProxyChannelManagerImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/StorageContainerProxyChannelManagerImplTest.java deleted file mode 100644 index bb94843fe06..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/routing/StorageContainerProxyChannelManagerImplTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.routing; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import io.grpc.Channel; -import io.grpc.stub.StreamObserver; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointRequest; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint; -import org.apache.bookkeeper.stream.proto.storage.StorageContainerServiceGrpc.StorageContainerServiceImplBase; -import org.junit.Test; - -/** - * Unit testing {@link StorageContainerProxyChannelManagerImpl}. - */ -public class StorageContainerProxyChannelManagerImplTest extends GrpcClientTestBase { - - private final long scId = 1234L; - private StorageContainerProxyChannelManagerImpl proxyChannelManager; - - @Override - protected void doSetup() throws Exception { - this.proxyChannelManager = new StorageContainerProxyChannelManagerImpl(serverManager); - } - - @Override - protected void doTeardown() throws Exception { - } - - - @Test - public void testGetStorageContainerChannel() throws Exception { - final CompletableFuture receivedRequest = new CompletableFuture<>(); - final CompletableFuture responseSupplier = new CompletableFuture<>(); - StorageContainerServiceImplBase scService = new StorageContainerServiceImplBase() { - @Override - public void getStorageContainerEndpoint( - GetStorageContainerEndpointRequest request, - StreamObserver responseObserver) { - receivedRequest.complete(request); - try { - responseObserver.onNext(responseSupplier.get()); - responseObserver.onCompleted(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - responseObserver.onError(e); - } catch (ExecutionException e) { - responseObserver.onError(e); - } - } - }; - serviceRegistry.addService(scService.bindService()); - - Channel channel = proxyChannelManager.getStorageContainerChannel(scId); - // if the location service doesn't respond, the channel will be null - assertNull(channel); - - // complete the location service request - responseSupplier.complete(getResponse(receivedRequest.get())); - while ((channel = proxyChannelManager.getStorageContainerChannel(scId)) == null) { - TimeUnit.MILLISECONDS.sleep(100); - } - assertNotNull(channel); - } - - private static GetStorageContainerEndpointResponse getResponse(GetStorageContainerEndpointRequest request) { - GetStorageContainerEndpointResponse.Builder respBuilder = - GetStorageContainerEndpointResponse.newBuilder(); - respBuilder.setStatusCode(StatusCode.SUCCESS); - for (OneStorageContainerEndpointRequest oneReq : request.getRequestsList()) { - OneStorageContainerEndpointResponse oneResp = OneStorageContainerEndpointResponse.newBuilder() - .setEndpoint(StorageContainerEndpoint.newBuilder() - .setStorageContainerId(oneReq.getStorageContainer()) - .setRevision(oneReq.getRevision() + 1) - .setRwEndpoint(ENDPOINT)) - .build(); - respBuilder.addResponses(oneResp); - } - return respBuilder.build(); - } - - - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerControllerTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerControllerTest.java deleted file mode 100644 index 8d01068a552..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerControllerTest.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.sc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.stream.proto.cluster.ClusterAssignmentData; -import org.apache.bookkeeper.stream.proto.cluster.ClusterMetadata; -import org.apache.bookkeeper.stream.proto.cluster.ServerAssignmentData; -import org.apache.bookkeeper.stream.storage.impl.sc.DefaultStorageContainerController.ServerAssignmentDataComparator; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Test; - -/** - * Unit test {@link DefaultStorageContainerController}. - */ -@Slf4j -public class DefaultStorageContainerControllerTest { - - private static final int NUM_STORAGE_CONTAINERS = 32; - - private final ClusterMetadata clusterMetadata; - private final StorageContainerController controller; - private final ClusterAssignmentData currentAssignment; - - public DefaultStorageContainerControllerTest() { - this.controller = new DefaultStorageContainerController(); - this.clusterMetadata = ClusterMetadata.newBuilder() - .setNumStorageContainers(NUM_STORAGE_CONTAINERS) - .build(); - this.currentAssignment = ClusterAssignmentData.newBuilder() - .putServers("default-server", ServerAssignmentData.newBuilder() - .addContainers(0L) - .addContainers(1L) - .addContainers(3L) - .build()) - .build(); - } - - @Test - public void testServerAssignmentDataComparator() { - ServerAssignmentDataComparator comparator = new ServerAssignmentDataComparator(); - - LinkedList serverList1 = new LinkedList<>(); - serverList1.add(1L); - LinkedList serverList2 = new LinkedList<>(); - serverList2.add(2L); - serverList2.add(3L); - - BookieId address1 = new BookieSocketAddress("127.0.0.1", 4181).toBookieId(); - BookieId address2 = new BookieSocketAddress("127.0.0.1", 4182).toBookieId(); - - Pair> pair1 = Pair.of(address1, serverList1); - Pair> pair2 = Pair.of(address1, serverList2); - Pair> pair3 = Pair.of(address2, serverList2); - - assertEquals(-1, comparator.compare(pair1, pair2)); - assertEquals(-1, comparator.compare(pair1, pair2)); - assertEquals( - Integer.compare(address1.hashCode(), address2.hashCode()), - comparator.compare(pair2, pair3)); - } - - @Test - public void testComputeIdealStateEmptyCluster() { - assertSame( - currentAssignment, - controller.computeIdealState( - clusterMetadata, - currentAssignment, - Collections.emptySet())); - } - - private static Set newCluster(int numServers) { - Set cluster = IntStream.range(0, numServers) - .mapToObj(idx -> new BookieSocketAddress("127.0.0.1", 4181 + idx).toBookieId()) - .collect(Collectors.toSet()); - return ImmutableSet.copyOf(cluster); - } - - private static Set newCluster(int numServers, int startServerIdx) { - Set cluster = IntStream.range(0, numServers) - .mapToObj(idx -> new BookieSocketAddress("127.0.0.1", 4181 + startServerIdx + idx).toBookieId()) - .collect(Collectors.toSet()); - return ImmutableSet.copyOf(cluster); - } - - private static void verifyAssignmentData(ClusterAssignmentData newAssignment, - Set currentCluster, - boolean isInitialIdealState) - throws Exception { - int numServers = currentCluster.size(); - - assertEquals(numServers, newAssignment.getServersCount()); - Set assignedContainers = Sets.newHashSet(); - Set assignedServers = Sets.newHashSet(); - - int numContainersPerServer = NUM_STORAGE_CONTAINERS / numServers; - int serverIdx = 0; - for (Map.Entry entry : newAssignment.getServersMap().entrySet()) { - log.info("Check assignment for server {} = {}", entry.getKey(), entry.getValue()); - - BookieId address = BookieId.parse(entry.getKey()); - assignedServers.add(address); - assertEquals(serverIdx + 1, assignedServers.size()); - - ServerAssignmentData serverData = entry.getValue(); - assertEquals(numContainersPerServer, serverData.getContainersCount()); - List containers = Lists.newArrayList(serverData.getContainersList()); - Collections.sort(containers); - assignedContainers.addAll(containers); - - if (isInitialIdealState) { - long startContainerId = containers.get(0); - for (int i = 0; i < containers.size(); i++) { - assertEquals(startContainerId + i * numServers, containers.get(i).longValue()); - } - } - ++serverIdx; - } - - // each server should be assigned with equal number of containers - assertTrue(Sets.difference(currentCluster, assignedServers).isEmpty()); - // all containers should be assigned - Set expectedContainers = LongStream.range(0L, NUM_STORAGE_CONTAINERS) - .boxed() - .collect(Collectors.toSet()); - assertTrue(Sets.difference(expectedContainers, assignedContainers).isEmpty()); - } - - private static void verifyAssignmentDataWhenHasMoreServers(ClusterAssignmentData newAssignment, - Set currentCluster) - throws Exception { - int numServers = currentCluster.size(); - - assertEquals(numServers, newAssignment.getServersCount()); - Set assignedContainers = Sets.newHashSet(); - Set assignedServers = Sets.newHashSet(); - - int numEmptyServers = 0; - int numAssignedServers = 0; - int serverIdx = 0; - for (Map.Entry entry : newAssignment.getServersMap().entrySet()) { - log.info("Check assignment for server {} = {}", entry.getKey(), entry.getValue()); - - BookieId address = BookieId.parse(entry.getKey()); - assignedServers.add(address); - assertEquals(serverIdx + 1, assignedServers.size()); - - ServerAssignmentData serverData = entry.getValue(); - if (serverData.getContainersCount() > 0) { - assertEquals(1, serverData.getContainersCount()); - ++numAssignedServers; - } else { - ++numEmptyServers; - } - List containers = Lists.newArrayList(serverData.getContainersList()); - Collections.sort(containers); - assignedContainers.addAll(containers); - - ++serverIdx; - } - - assertEquals(numServers / 2, numEmptyServers); - assertEquals(numServers / 2, numAssignedServers); - - // each server should be assigned with equal number of containers - assertTrue(Sets.difference(currentCluster, assignedServers).isEmpty()); - // all containers should be assigned - Set expectedContainers = LongStream.range(0L, NUM_STORAGE_CONTAINERS) - .boxed() - .collect(Collectors.toSet()); - assertTrue(Sets.difference(expectedContainers, assignedContainers).isEmpty()); - } - - @Test - public void testComputeIdealStateFromEmptyAssignment() throws Exception { - ClusterAssignmentData emptyAssignment = ClusterAssignmentData.newBuilder().build(); - - int numServers = 8; - Set currentCluster = newCluster(numServers); - - ClusterAssignmentData newAssignment = controller.computeIdealState( - clusterMetadata, - emptyAssignment, - currentCluster); - - verifyAssignmentData(newAssignment, currentCluster, true); - } - - @Test - public void testComputeIdealStateIfClusterUnchanged() throws Exception { - ClusterAssignmentData emptyAssignment = ClusterAssignmentData.newBuilder().build(); - - int numServers = 8; - Set currentCluster = newCluster(numServers); - ClusterAssignmentData newAssignment = controller.computeIdealState( - clusterMetadata, - emptyAssignment, - currentCluster); - verifyAssignmentData(newAssignment, currentCluster, true); - - ClusterAssignmentData newAssignment2 = controller.computeIdealState( - clusterMetadata, - newAssignment, - currentCluster); - - // the state should not change if cluster is unchanged. - assertSame(newAssignment, newAssignment2); - } - - @Test - public void testComputeIdealStateWhenHostsRemoved() throws Exception { - ClusterAssignmentData emptyAssignment = ClusterAssignmentData.newBuilder().build(); - - int numServers = 8; - Set currentCluster = newCluster(numServers); - - ClusterAssignmentData assignmentData = controller.computeIdealState( - clusterMetadata, - emptyAssignment, - currentCluster); - verifyAssignmentData(assignmentData, currentCluster, true); - - int newNumServers = 4; - Set newCluster = newCluster(newNumServers); - - ClusterAssignmentData newAssignmentData = controller.computeIdealState( - clusterMetadata, - assignmentData, - newCluster); - verifyAssignmentData(newAssignmentData, newCluster, false); - } - - @Test - public void testComputeIdealStateWhenHostsAdded() throws Exception { - ClusterAssignmentData emptyAssignment = ClusterAssignmentData.newBuilder().build(); - - int numServers = 4; - Set currentCluster = newCluster(numServers); - - ClusterAssignmentData assignmentData = controller.computeIdealState( - clusterMetadata, - emptyAssignment, - currentCluster); - verifyAssignmentData(assignmentData, currentCluster, true); - - int newNumServers = 8; - Set newCluster = newCluster(newNumServers); - - ClusterAssignmentData newAssignmentData = controller.computeIdealState( - clusterMetadata, - assignmentData, - newCluster); - verifyAssignmentData(newAssignmentData, newCluster, false); - } - - @Test - public void testComputeIdealStateWhenHostsRemovedAdded() throws Exception { - ClusterAssignmentData emptyAssignment = ClusterAssignmentData.newBuilder().build(); - - int numServers = 4; - Set currentCluster = newCluster(numServers); - - ClusterAssignmentData assignmentData = controller.computeIdealState( - clusterMetadata, - emptyAssignment, - currentCluster); - verifyAssignmentData(assignmentData, currentCluster, true); - - Set serversToAdd = newCluster(6, numServers); - Set serversToRemove = newCluster(2); - - Set newCluster = Sets.newHashSet(currentCluster); - newCluster.addAll(serversToAdd); - serversToRemove.forEach(newCluster::remove); - - ClusterAssignmentData newAssignmentData = controller.computeIdealState( - clusterMetadata, - assignmentData, - newCluster); - verifyAssignmentData(newAssignmentData, newCluster, false); - } - - @Test - public void testComputeIdealStateWhenHasMoreServers() throws Exception { - ClusterAssignmentData emptyAssignment = ClusterAssignmentData.newBuilder().build(); - - int numServers = 2 * NUM_STORAGE_CONTAINERS; - Set currentCluster = newCluster(numServers); - - ClusterAssignmentData assignmentData = controller.computeIdealState( - clusterMetadata, - emptyAssignment, - currentCluster); - verifyAssignmentDataWhenHasMoreServers(assignmentData, currentCluster); - } - - @Test - public void testComputeIdealStateWhenScaleToMoreServers() throws Exception { - ClusterAssignmentData emptyAssignment = ClusterAssignmentData.newBuilder().build(); - - int numServers = 4; - Set currentCluster = newCluster(numServers); - - ClusterAssignmentData assignmentData = controller.computeIdealState( - clusterMetadata, - emptyAssignment, - currentCluster); - verifyAssignmentData(assignmentData, currentCluster, true); - - numServers = 2 * NUM_STORAGE_CONTAINERS; - Set newCluster = newCluster(numServers); - ClusterAssignmentData newAssignment = controller.computeIdealState( - clusterMetadata, - assignmentData, - newCluster); - verifyAssignmentDataWhenHasMoreServers(newAssignment, newCluster); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java deleted file mode 100644 index a56623bf510..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.sc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerService; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerServiceFactory; -import org.junit.Test; - -/** - * Unit test for {@link DefaultStorageContainerFactory}. - */ -public class TestDefaultStorageContainerFactory { - - @Test - public void testCreate() { - StorageContainerServiceFactory mockServiceFactory = - mock(StorageContainerServiceFactory.class); - StorageContainerService mockService = mock(StorageContainerService.class); - - when(mockServiceFactory.createStorageContainerService(anyLong())) - .thenReturn(mockService); - - DefaultStorageContainerFactory factory = new DefaultStorageContainerFactory(mockServiceFactory); - StorageContainer sc = factory.createStorageContainer(1234L); - assertTrue(sc instanceof StorageContainerImpl); - assertEquals(1234L, sc.getId()); - } -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerPlacementPolicyImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerPlacementPolicyImpl.java deleted file mode 100644 index 009d3c069f6..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerPlacementPolicyImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed 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. - */ - -package org.apache.bookkeeper.stream.storage.impl.sc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test of {@link StorageContainerPlacementPolicyImpl}. - */ -public class TestStorageContainerPlacementPolicyImpl { - - @Test - public void testPlacement() { - int numStorageContainers = 1024; - StorageContainerPlacementPolicyImpl placementPolicy = - StorageContainerPlacementPolicyImpl.of(numStorageContainers); - assertEquals(numStorageContainers, placementPolicy.getNumStorageContainers()); - long scId = placementPolicy.placeStreamRange(1234L, 5678L); - assertTrue(scId >= 0 && scId < placementPolicy.getNumStorageContainers()); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java deleted file mode 100644 index 837dbe2ccf3..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed 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. - */ -package org.apache.bookkeeper.stream.storage.impl.sc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.exceptions.ObjectClosedException; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerFactory; -import org.apache.bookkeeper.stream.storage.exceptions.StorageException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link StorageContainerRegistryImpl}. - */ -public class TestStorageContainerRegistryImpl { - - private OrderedScheduler scheduler; - - @Before - public void setUp() { - this.scheduler = OrderedScheduler.newSchedulerBuilder() - .numThreads(1) - .name("test-storage-container-registry-impl") - .build(); - } - - @After - public void tearDown() { - if (null != this.scheduler) { - this.scheduler.shutdown(); - } - } - - private StorageContainer createStorageContainer() { - StorageContainer sc = mock(StorageContainer.class); - when(sc.start()).thenReturn(FutureUtils.value(sc)); - when(sc.stop()).thenReturn(FutureUtils.value(null)); - return sc; - } - - private StorageContainerFactory createStorageContainerFactory() { - return scId -> createStorageContainer(); - } - - @Test - public void testOperationsAfterClosed() throws Exception { - StorageContainerFactory scFactory = createStorageContainerFactory(); - StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory); - registry.close(); - - long scId = 1234L; - - try { - FutureUtils.result(registry.startStorageContainer(scId)); - fail("Should fail to start storage container after registry is closed"); - } catch (ObjectClosedException oce) { - // expected - assertEquals(0, registry.getNumStorageContainers()); - } - - try { - FutureUtils.result(registry.stopStorageContainer(scId)); - fail("Should fail to start storage container after registry is closed"); - } catch (ObjectClosedException oce) { - // expected - assertEquals(0, registry.getNumStorageContainers()); - } - } - - @Test - public void testStopNotFoundStorageContainer() throws Exception { - StorageContainerFactory scFactory = createStorageContainerFactory(); - StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory); - FutureUtils.result(registry.stopStorageContainer(1234L)); - assertEquals(0, registry.getNumStorageContainers()); - } - - @Test - public void testStartStorageContainerTwice() throws Exception { - StorageContainerFactory scFactory = createStorageContainerFactory(); - StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory); - FutureUtils.result(registry.startStorageContainer(1234L)); - assertEquals(1, registry.getNumStorageContainers()); - // second time - try { - FutureUtils.result(registry.startStorageContainer(1234L)); - fail("Should fail on starting same storage container twice"); - } catch (StorageException ue) { - assertEquals(1, registry.getNumStorageContainers()); - } - } - - @Test - public void testStartStopStorageContainers() throws Exception { - StorageContainer sc1 = createStorageContainer(); - StorageContainer sc2 = createStorageContainer(); - StorageContainerFactory factory = scId -> { - if (scId == 1L) { - return sc1; - } else { - return sc2; - } - }; - - long scId = 1L; - - StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(factory); - FutureUtils.result(registry.startStorageContainer(scId)); - assertEquals(1, registry.getNumStorageContainers()); - assertEquals(sc1, registry.getStorageContainer(scId)); - - scId = 2L; - FutureUtils.result(registry.startStorageContainer(scId)); - assertEquals(2, registry.getNumStorageContainers()); - assertEquals(sc1, registry.getStorageContainer(1L)); - assertEquals(sc2, registry.getStorageContainer(2L)); - - FutureUtils.result(registry.stopStorageContainer(scId)); - assertEquals(1, registry.getNumStorageContainers()); - assertEquals(sc1, registry.getStorageContainer(1L)); - - registry.close(); - verify(sc1, times(1)).close(); - assertEquals(0, registry.getNumStorageContainers()); - - // double close - registry.close(); - verify(sc1, times(1)).close(); - } - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java deleted file mode 100644 index 3a5a4fd7bc3..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.sc; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.clients.utils.NetUtils; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.testing.MoreAsserts; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stream.proto.cluster.ClusterAssignmentData; -import org.apache.bookkeeper.stream.proto.cluster.ServerAssignmentData; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerFactory; -import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerRegistry; -import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration; -import org.apache.bookkeeper.stream.storage.impl.cluster.ZkClusterMetadataStore; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.curator.framework.CuratorFramework; -import org.apache.curator.framework.CuratorFrameworkFactory; -import org.apache.curator.retry.ExponentialBackoffRetry; -import org.apache.distributedlog.ZooKeeperClusterTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Unit test {@link ZkStorageContainerManager}. - */ -public class ZkStorageContainerManagerTest extends ZooKeeperClusterTestCase { - - private static final int NUM_STORAGE_CONTAINERS = 32; - - @Rule - public final TestName runtime = new TestName(); - - private final Endpoint myEndpoint = Endpoint.newBuilder() - .setHostname("127.0.0.1") - .setPort(4181) - .build(); - - private CuratorFramework curatorClient; - private StorageContainerFactory mockScFactory; - private StorageContainerRegistry scRegistry; - private ZkClusterMetadataStore clusterMetadataStore; - private ZkStorageContainerManager scManager; - - @Before - public void setup() { - curatorClient = CuratorFrameworkFactory.newClient( - zkServers, - new ExponentialBackoffRetry(200, 10, 5000)); - curatorClient.start(); - - clusterMetadataStore = spy(new ZkClusterMetadataStore( - curatorClient, zkServers, "/" + runtime.getMethodName())); - clusterMetadataStore.initializeCluster(NUM_STORAGE_CONTAINERS); - - mockScFactory = mock(StorageContainerFactory.class); - scRegistry = spy(new StorageContainerRegistryImpl(mockScFactory)); - - scManager = new ZkStorageContainerManager( - myEndpoint, - new StorageConfiguration(new CompositeConfiguration()) - .setClusterControllerScheduleInterval(1, TimeUnit.SECONDS), - clusterMetadataStore, - scRegistry, - NullStatsLogger.INSTANCE); - } - - @After - public void teardown() { - if (null != scManager) { - scManager.close(); - } - - if (null != curatorClient) { - curatorClient.close(); - } - - if (null != clusterMetadataStore) { - clusterMetadataStore.close(); - } - } - - private static StorageContainer createStorageContainer(long scId, - CompletableFuture startFuture, - CompletableFuture stopFuture) { - StorageContainer sc = mock(StorageContainer.class); - when(sc.getId()).thenReturn(scId); - when(sc.start()).thenReturn(startFuture); - when(sc.stop()).thenReturn(stopFuture); - return sc; - } - - /** - * Test basic operations such as starting or stopping containers. - */ - @Test - public void testBasicOps() throws Exception { - // start the storage container manager - scManager.start(); - - long containerId = 11L; - long containerId2 = 22L; - - // mock a container and start it in the registry - CompletableFuture startFuture = new CompletableFuture<>(); - CompletableFuture stopFuture = new CompletableFuture<>(); - CompletableFuture startFuture2 = new CompletableFuture<>(); - CompletableFuture stopFuture2 = new CompletableFuture<>(); - - StorageContainer mockSc = createStorageContainer(containerId, startFuture, stopFuture); - when(mockScFactory.createStorageContainer(eq(containerId))) - .thenReturn(mockSc); - - StorageContainer mockSc2 = createStorageContainer(containerId2, startFuture2, stopFuture2); - when(mockScFactory.createStorageContainer(eq(containerId2))) - .thenReturn(mockSc2); - - // update assignment map - ClusterAssignmentData cad = ClusterAssignmentData.newBuilder() - .putServers( - NetUtils.endpointToString(myEndpoint), - ServerAssignmentData.newBuilder() - .addContainers(containerId) - .build()) - .build(); - clusterMetadataStore.updateClusterAssignmentData(cad); - - // notify the container to complete startup - startFuture.complete(mockSc); - verify(scRegistry, timeout(10000).times(1)).startStorageContainer(eq(containerId)); - MoreAsserts.assertUtil( - ignored -> scManager.getLiveContainers().size() >= 1, - () -> null); - assertEquals(1, scManager.getLiveContainers().size()); - assertTrue(scManager.getLiveContainers().containsKey(containerId)); - - - // update assignment map to remove containerId and add containerId2 - ClusterAssignmentData newCad = ClusterAssignmentData.newBuilder() - .putServers( - NetUtils.endpointToString(myEndpoint), - ServerAssignmentData.newBuilder() - .addContainers(22L) - .build()) - .build(); - clusterMetadataStore.updateClusterAssignmentData(newCad); - - // notify the container1 to stop and container2 to start - FutureUtils.complete(stopFuture, null); - startFuture2.complete(mockSc2); - verify(scRegistry, timeout(10000).times(1)).stopStorageContainer(eq(containerId), same(mockSc)); - verify(scRegistry, timeout(10000).times(1)).startStorageContainer(eq(containerId2)); - MoreAsserts.assertUtil( - ignored -> !scManager.getLiveContainers().containsKey(containerId) - && scManager.getLiveContainers().containsKey(containerId2), - () -> null); - assertEquals(1, scManager.getLiveContainers().size()); - assertFalse(scManager.getLiveContainers().containsKey(containerId)); - assertTrue(scManager.getLiveContainers().containsKey(containerId2)); - } - - @Test - public void testShutdownPendingStartStorageContainer() throws Exception { - // start the storage container manager - scManager.start(); - - long containerId = 11L; - - // mock a container and start it in the registry - CompletableFuture startFuture = new CompletableFuture<>(); - CompletableFuture stopFuture = new CompletableFuture<>(); - - StorageContainer mockSc = createStorageContainer( - containerId, startFuture, stopFuture); - when(mockScFactory.createStorageContainer(eq(containerId))) - .thenReturn(mockSc); - - // update assignment map - ClusterAssignmentData cad = ClusterAssignmentData.newBuilder() - .putServers( - NetUtils.endpointToString(myEndpoint), - ServerAssignmentData.newBuilder() - .addContainers(containerId) - .build()) - .build(); - clusterMetadataStore.updateClusterAssignmentData(cad); - - // wait until container start is called - verify(scRegistry, timeout(10000).times(1)).startStorageContainer(eq(containerId)); - assertEquals(0, scManager.getLiveContainers().size()); - assertEquals(1, scManager.getPendingStartStopContainers().size()); - assertTrue(scManager.getPendingStartStopContainers().contains(containerId)); - - // now shutting the manager down - cad = ClusterAssignmentData.newBuilder().build(); - clusterMetadataStore.updateClusterAssignmentData(cad); - - // the container should not be stopped since it is pending starting. - Thread.sleep(200); - verify(scRegistry, timeout(10000).times(0)).stopStorageContainer(eq(containerId), same(mockSc)); - assertEquals(1, scManager.getPendingStartStopContainers().size()); - assertTrue(scManager.getPendingStartStopContainers().contains(containerId)); - - // now complete the start future and the container is eventually going to shutdown - FutureUtils.complete(startFuture, mockSc); - FutureUtils.complete(stopFuture, null); - - verify(scRegistry, timeout(10000).times(1)).stopStorageContainer(eq(containerId), same(mockSc)); - MoreAsserts.assertUtil( - ignored -> scManager.getPendingStartStopContainers().size() == 0, - () -> null); - assertEquals(0, scManager.getLiveContainers().size()); - assertEquals(0, scManager.getPendingStartStopContainers().size()); - } - - @Test - public void testStartContainerOnFailures() throws Exception { - scManager.close(); - - long containerId = 11L; - AtomicBoolean returnGoodContainer = new AtomicBoolean(false); - - CompletableFuture startFuture = new CompletableFuture<>(); - StorageContainer goodSc = createStorageContainer(containerId, startFuture, FutureUtils.Void()); - mockScFactory = (scId) -> { - if (returnGoodContainer.get()) { - return goodSc; - } else { - return createStorageContainer( - scId, - FutureUtils.exception(new Exception("Failed to start")), - FutureUtils.Void() - ); - } - }; - scRegistry = spy(new StorageContainerRegistryImpl(mockScFactory)); - - scManager = new ZkStorageContainerManager( - myEndpoint, - new StorageConfiguration(new CompositeConfiguration()) - .setClusterControllerScheduleInterval(1, TimeUnit.SECONDS), - clusterMetadataStore, - scRegistry, - NullStatsLogger.INSTANCE); - - - // start the storage container manager - scManager.start(); - - // update assignment map - ClusterAssignmentData cad = ClusterAssignmentData.newBuilder() - .putServers( - NetUtils.endpointToString(myEndpoint), - ServerAssignmentData.newBuilder() - .addContainers(containerId) - .build()) - .build(); - clusterMetadataStore.updateClusterAssignmentData(cad); - - // wait until container start is called and verify it is not started. - verify(scRegistry, timeout(10000).atLeastOnce()).startStorageContainer(eq(containerId)); - assertEquals(0, scManager.getLiveContainers().size()); - - // flip the flag to return a good container to simulate successful startup - returnGoodContainer.set(true); - FutureUtils.complete(startFuture, goodSc); - - // wait until container start is called again and the container is started - MoreAsserts.assertUtil( - ignored -> scManager.getLiveContainers().size() >= 1, - () -> null); - assertEquals(1, scManager.getLiveContainers().size()); - assertTrue(scManager.getLiveContainers().containsKey(containerId)); - } - - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java deleted file mode 100644 index 6b678393605..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.service; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_RANGE_ID; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_STREAM_ID; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_RANGE_ID; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STREAM_ID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.clients.impl.internal.api.StorageServerClientManager; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse; -import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest; -import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.CreateStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest; -import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest; -import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse; -import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest; -import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse; -import org.apache.bookkeeper.stream.protocol.RangeId; -import org.apache.bookkeeper.stream.storage.api.kv.TableStore; -import org.apache.bookkeeper.stream.storage.api.metadata.MetaRangeStore; -import org.apache.bookkeeper.stream.storage.api.metadata.RootRangeStore; -import org.apache.bookkeeper.stream.storage.impl.kv.TableStoreFactory; -import org.apache.bookkeeper.stream.storage.impl.metadata.MetaRangeStoreFactory; -import org.apache.bookkeeper.stream.storage.impl.metadata.RootRangeStoreFactory; -import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link RangeStoreServiceImpl}. - */ -public class RangeStoreServiceImplTest { - - private static final long SCID = 3456L; - private static final long STREAM_ID = 1234L; - private static final long RANGE_ID = 3456L; - private static final RangeId RID = RangeId.of(STREAM_ID, RANGE_ID); - - private MVCCStoreFactory mvccStoreFactory; - private RootRangeStoreFactory rrStoreFactory; - private MetaRangeStoreFactory mrStoreFactory; - private TableStoreFactory tableStoreFactory; - private RangeStoreServiceImpl container; - private OrderedScheduler scheduler; - private RootRangeStore rrStore; - private MVCCAsyncStore rrMvccStore; - private MetaRangeStore mrStore; - private MVCCAsyncStore mrMvccStore; - private TableStore trStore; - private MVCCAsyncStore trMvccStore; - - private StorageServerClientManager clientManager; - - @SuppressWarnings("unchecked") - @Before - public void setUp() { - this.scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-scheduler") - .numThreads(1) - .build(); - this.mvccStoreFactory = mock(MVCCStoreFactory.class); - this.rrStoreFactory = mock(RootRangeStoreFactory.class); - this.mrStoreFactory = mock(MetaRangeStoreFactory.class); - this.tableStoreFactory = mock(TableStoreFactory.class); - - this.rrMvccStore = mock(MVCCAsyncStore.class); - this.mrMvccStore = mock(MVCCAsyncStore.class); - this.trMvccStore = mock(MVCCAsyncStore.class); - - this.clientManager = mock(StorageServerClientManager.class); - - this.container = new RangeStoreServiceImpl( - SCID, - scheduler, - mvccStoreFactory, - clientManager, - rrStoreFactory, - mrStoreFactory, - tableStoreFactory); - - assertEquals(SCID, this.container.getId()); - } - - @After - public void tearDown() { - if (null != scheduler) { - scheduler.shutdown(); - } - } - - private void mockStorageContainer(long scId) { - when(mvccStoreFactory.openStore( - eq(ROOT_STORAGE_CONTAINER_ID), - eq(ROOT_STREAM_ID), - eq(ROOT_RANGE_ID), - eq(0)) - ).thenReturn(FutureUtils.value(rrMvccStore)); - when(mvccStoreFactory.openStore( - eq(scId), - eq(CONTAINER_META_STREAM_ID), - eq(CONTAINER_META_RANGE_ID), - eq(0)) - ).thenReturn(FutureUtils.value(mrMvccStore)); - when(mvccStoreFactory.openStore( - eq(scId), - eq(STREAM_ID), - eq(RANGE_ID), - anyInt()) - ).thenReturn(FutureUtils.value(trMvccStore)); - this.rrStore = mock(RootRangeStore.class); - when(rrStoreFactory.createStore(eq(rrMvccStore))) - .thenReturn(rrStore); - this.mrStore = mock(MetaRangeStore.class); - when(mrStoreFactory.createStore(eq(mrMvccStore))) - .thenReturn(mrStore); - this.trStore = mock(TableStore.class); - when(tableStoreFactory.createStore(eq(trMvccStore))) - .thenReturn(trStore); - when(clientManager.getStreamProperties(eq(STREAM_ID))) - .thenReturn(FutureUtils.value(StreamProperties.getDefaultInstance())); - } - - @Test - public void testStart() throws Exception { - mockStorageContainer(SCID); - - FutureUtils.result(container.start()); - - // root range is not started because it is not the root container - verify(mvccStoreFactory, times(0)) - .openStore(eq(ROOT_STORAGE_CONTAINER_ID), eq(ROOT_STREAM_ID), eq(ROOT_RANGE_ID), eq(0)); - verify(rrStoreFactory, times(0)) - .createStore(eq(rrMvccStore)); - - // meta range should be started - verify(mvccStoreFactory, times(1)) - .openStore(eq(SCID), eq(CONTAINER_META_STREAM_ID), eq(CONTAINER_META_RANGE_ID), eq(0)); - verify(mrStoreFactory, times(1)) - .createStore(eq(mrMvccStore)); - } - - @Test - public void testStartRootContainer() throws Exception { - mockStorageContainer(ROOT_STORAGE_CONTAINER_ID); - - RangeStoreServiceImpl container = new RangeStoreServiceImpl( - ROOT_STORAGE_CONTAINER_ID, - scheduler, - mvccStoreFactory, - clientManager, - rrStoreFactory, - mrStoreFactory, - tableStoreFactory); - FutureUtils.result(container.start()); - - // root range is not started because it is not the root container - verify(mvccStoreFactory, times(1)) - .openStore(eq(ROOT_STORAGE_CONTAINER_ID), eq(ROOT_STREAM_ID), eq(ROOT_RANGE_ID), eq(0)); - verify(rrStoreFactory, times(1)) - .createStore(eq(rrMvccStore)); - - // meta range should be started - verify(mvccStoreFactory, times(1)) - .openStore(eq(ROOT_STORAGE_CONTAINER_ID), eq(CONTAINER_META_STREAM_ID), eq(CONTAINER_META_RANGE_ID), eq(0)); - verify(mrStoreFactory, times(1)) - .createStore(eq(mrMvccStore)); - } - - @Test - public void testClose() throws Exception { - mockStorageContainer(SCID); - - when(mvccStoreFactory.closeStores(eq(SCID))) - .thenReturn(FutureUtils.Void()); - - FutureUtils.result(container.stop()); - - verify(mvccStoreFactory, times(1)) - .closeStores(eq(SCID)); - } - - // - // Root Range Methods - // - - @Test - public void testCreateNamespace() throws Exception { - mockStorageContainer(SCID); - - CreateNamespaceResponse expectedResp = CreateNamespaceResponse.getDefaultInstance(); - when(rrStore.createNamespace(any(CreateNamespaceRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - CreateNamespaceRequest expectedReq = CreateNamespaceRequest.getDefaultInstance(); - assertSame( - expectedResp, - FutureUtils.result(rrStore.createNamespace(expectedReq))); - verify(rrStore, times(1)) - .createNamespace(same(expectedReq)); - } - - @Test - public void testDeleteNamespace() throws Exception { - mockStorageContainer(SCID); - - DeleteNamespaceResponse expectedResp = DeleteNamespaceResponse.getDefaultInstance(); - when(rrStore.deleteNamespace(any(DeleteNamespaceRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - DeleteNamespaceRequest expectedReq = DeleteNamespaceRequest.getDefaultInstance(); - assertSame( - expectedResp, - FutureUtils.result(rrStore.deleteNamespace(expectedReq))); - verify(rrStore, times(1)) - .deleteNamespace(same(expectedReq)); - } - - @Test - public void testGetNamespace() throws Exception { - mockStorageContainer(SCID); - - GetNamespaceResponse expectedResp = GetNamespaceResponse.getDefaultInstance(); - when(rrStore.getNamespace(any(GetNamespaceRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - GetNamespaceRequest expectedReq = GetNamespaceRequest.getDefaultInstance(); - assertSame( - expectedResp, - FutureUtils.result(rrStore.getNamespace(expectedReq))); - verify(rrStore, times(1)) - .getNamespace(same(expectedReq)); - } - - @Test - public void testCreateStream() throws Exception { - mockStorageContainer(SCID); - - CreateStreamResponse expectedResp = CreateStreamResponse.getDefaultInstance(); - when(rrStore.createStream(any(CreateStreamRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - CreateStreamRequest expectedReq = CreateStreamRequest.getDefaultInstance(); - assertSame( - expectedResp, - FutureUtils.result(rrStore.createStream(expectedReq))); - verify(rrStore, times(1)) - .createStream(same(expectedReq)); - } - - @Test - public void testDeleteStream() throws Exception { - mockStorageContainer(SCID); - - DeleteStreamResponse expectedResp = DeleteStreamResponse.getDefaultInstance(); - when(rrStore.deleteStream(any(DeleteStreamRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - DeleteStreamRequest expectedReq = DeleteStreamRequest.getDefaultInstance(); - assertSame( - expectedResp, - FutureUtils.result(rrStore.deleteStream(expectedReq))); - verify(rrStore, times(1)) - .deleteStream(same(expectedReq)); - } - - @Test - public void testGetStream() throws Exception { - mockStorageContainer(SCID); - - GetStreamResponse expectedResp = GetStreamResponse.getDefaultInstance(); - when(rrStore.getStream(any(GetStreamRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - GetStreamRequest expectedReq = GetStreamRequest.getDefaultInstance(); - assertSame( - expectedResp, - FutureUtils.result(rrStore.getStream(expectedReq))); - verify(rrStore, times(1)) - .getStream(same(expectedReq)); - } - - // - // Meta Range Methods - // - - @Test - public void testGetActiveRanges() throws Exception { - mockStorageContainer(SCID); - - GetActiveRangesResponse expectedResp = GetActiveRangesResponse.getDefaultInstance(); - when(mrStore.getActiveRanges(any(GetActiveRangesRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - GetActiveRangesRequest expectedReq = GetActiveRangesRequest.getDefaultInstance(); - assertSame( - expectedResp, - FutureUtils.result(mrStore.getActiveRanges(expectedReq))); - verify(mrStore, times(1)) - .getActiveRanges(same(expectedReq)); - } - - // - // Table API - // - - private PutRequest newPutRequest() { - RoutingHeader header = RoutingHeader.newBuilder() - .setStreamId(STREAM_ID) - .setRangeId(RANGE_ID) - .build(); - return PutRequest.newBuilder() - .setHeader(header) - .build(); - } - - private DeleteRangeRequest newDeleteRequest() { - RoutingHeader header = RoutingHeader.newBuilder() - .setStreamId(STREAM_ID) - .setRangeId(RANGE_ID) - .build(); - return DeleteRangeRequest.newBuilder() - .setHeader(header) - .build(); - } - - private RangeRequest newRangeRequest() { - RoutingHeader header = RoutingHeader.newBuilder() - .setStreamId(STREAM_ID) - .setRangeId(RANGE_ID) - .build(); - return RangeRequest.newBuilder() - .setHeader(header) - .build(); - } - - private IncrementRequest newIncrRequest() { - RoutingHeader header = RoutingHeader.newBuilder() - .setStreamId(STREAM_ID) - .setRangeId(RANGE_ID) - .build(); - return IncrementRequest.newBuilder() - .setHeader(header) - .build(); - } - - private TxnRequest newTxnRequest() { - RoutingHeader header = RoutingHeader.newBuilder() - .setStreamId(STREAM_ID) - .setRangeId(RANGE_ID) - .build(); - return TxnRequest.newBuilder() - .setHeader(header) - .build(); - } - - @Test - public void testRangeWhenTableStoreNotCached() throws Exception { - mockStorageContainer(SCID); - - RangeResponse expectedResp = RangeResponse.getDefaultInstance(); - when(trStore.range(any(RangeRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - RangeRequest request = newRangeRequest(); - RangeResponse response = FutureUtils.result(container.range(request)); - assertSame(expectedResp, response); - assertSame(trStore, container.getTableStoreCache().getTableStore(RID)); - } - - @Test - public void testRangeWhenTableStoreCached() throws Exception { - mockStorageContainer(SCID); - - RangeResponse expectedResp = RangeResponse.getDefaultInstance(); - when(trStore.range(any(RangeRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - container.getTableStoreCache().getTableStores().put(RID, trStore); - - RangeRequest request = newRangeRequest(); - RangeResponse response = FutureUtils.result(container.range(request)); - assertSame(expectedResp, response); - } - - @Test - public void testPutWhenTableStoreNotCached() throws Exception { - mockStorageContainer(SCID); - - PutResponse expectedResp = PutResponse.getDefaultInstance(); - when(trStore.put(any(PutRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - PutRequest request = newPutRequest(); - PutResponse response = FutureUtils.result(container.put(request)); - assertSame(expectedResp, response); - assertSame(trStore, container.getTableStoreCache().getTableStore(RID)); - } - - @Test - public void testPutWhenTableStoreCached() throws Exception { - mockStorageContainer(SCID); - - PutResponse expectedResp = PutResponse.getDefaultInstance(); - when(trStore.put(any(PutRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - container.getTableStoreCache().getTableStores().put(RID, trStore); - - PutRequest request = newPutRequest(); - PutResponse response = FutureUtils.result(container.put(request)); - assertSame(expectedResp, response); - } - - @Test - public void testDeleteWhenTableStoreNotCached() throws Exception { - mockStorageContainer(SCID); - - DeleteRangeResponse expectedResp = DeleteRangeResponse.getDefaultInstance(); - when(trStore.delete(any(DeleteRangeRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - DeleteRangeRequest request = newDeleteRequest(); - DeleteRangeResponse response = FutureUtils.result(container.delete(request)); - assertSame(expectedResp, response); - assertSame(trStore, container.getTableStoreCache().getTableStore(RID)); - } - - @Test - public void testDeleteWhenTableStoreCached() throws Exception { - mockStorageContainer(SCID); - - DeleteRangeResponse expectedResp = DeleteRangeResponse.getDefaultInstance(); - when(trStore.delete(any(DeleteRangeRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - container.getTableStoreCache().getTableStores().put(RID, trStore); - - DeleteRangeRequest request = newDeleteRequest(); - DeleteRangeResponse response = FutureUtils.result(container.delete(request)); - assertSame(expectedResp, response); - } - - @Test - public void testTxnWhenTableStoreNotCached() throws Exception { - mockStorageContainer(SCID); - - TxnResponse expectedResp = TxnResponse.getDefaultInstance(); - when(trStore.txn(any(TxnRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - - TxnRequest request = newTxnRequest(); - TxnResponse response = FutureUtils.result(container.txn(request)); - assertSame(expectedResp, response); - assertSame(trStore, container.getTableStoreCache().getTableStore(RID)); - } - - @Test - public void testTxnWhenTableStoreCached() throws Exception { - mockStorageContainer(SCID); - - TxnResponse expectedResp = TxnResponse.getDefaultInstance(); - when(trStore.txn(any(TxnRequest.class))) - .thenReturn(FutureUtils.value(expectedResp)); - container.getTableStoreCache().getTableStores().put(RID, trStore); - - TxnRequest request = newTxnRequest(); - TxnResponse response = FutureUtils.result(container.txn(request)); - assertSame(expectedResp, response); - } -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCAsyncStoreTestBase.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCAsyncStoreTestBase.java deleted file mode 100644 index de3bc8171dc..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCAsyncStoreTestBase.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.store; - -import static org.apache.bookkeeper.statelib.impl.mvcc.MVCCUtils.NOP_CMD; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import org.apache.bookkeeper.common.coder.ByteArrayCoder; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.statelib.StateStores; -import org.apache.bookkeeper.statelib.api.StateStoreSpec; -import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.LogRecord; -import org.apache.distributedlog.LogRecordWithDLSN; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.namespace.Namespace; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; -import org.junit.rules.Timeout; - -/** - * An abstract test base that provides a mvcc store. - */ -public abstract class MVCCAsyncStoreTestBase { - - private static Namespace mockNamespace() throws Exception { - Namespace namespace = mock(Namespace.class); - DistributedLogManager dlm = mock(DistributedLogManager.class); - when(dlm.asyncClose()).thenReturn(FutureUtils.Void()); - when(namespace.openLog(anyString())).thenReturn(dlm); - AsyncLogWriter logWriter = mock(AsyncLogWriter.class); - when(dlm.openAsyncLogWriter()).thenReturn(FutureUtils.value(logWriter)); - when(dlm.openAsyncLogWriter(any())).thenReturn(FutureUtils.value(logWriter)); - when(logWriter.getLastTxId()).thenReturn(-1L); - DLSN dlsn = new DLSN(0L, 0L, 0L); - when(logWriter.write(any(LogRecord.class))).thenReturn(FutureUtils.value(dlsn)); - when(logWriter.asyncClose()).thenReturn(FutureUtils.Void()); - AsyncLogReader logReader = mock(AsyncLogReader.class); - when(dlm.openAsyncLogReader(anyLong())).thenReturn(FutureUtils.value(logReader)); - when(logReader.asyncClose()).thenReturn(FutureUtils.Void()); - LogRecordWithDLSN record = new LogRecordWithDLSN( - dlsn, 0L, NOP_CMD.toByteArray(), 0L); - when(logReader.readNext()).thenReturn(FutureUtils.value(record)); - return namespace; - } - - @Rule - public TestName name = new TestName(); - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - @Rule - public final Timeout globalTimeout = Timeout.seconds(10); - - protected Namespace namespace; - protected MVCCAsyncStore store; - protected OrderedScheduler scheduler; - - @Before - public void setUp() throws Exception { - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("test-root-range-store") - .numThreads(1) - .build(); - - namespace = mockNamespace(); - - File localStateDir = testDir.newFolder(name.getMethodName()); - StateStoreSpec spec = StateStoreSpec.builder() - .name(name.getMethodName()) - .keyCoder(ByteArrayCoder.of()) - .valCoder(ByteArrayCoder.of()) - .localStateStoreDir(localStateDir) - .stream(name.getMethodName()) - .writeIOScheduler(scheduler.chooseThread()) - .readIOScheduler(scheduler.chooseThread()) - .checkpointIOScheduler(null) - .build(); - store = StateStores.mvccKvBytesStoreSupplier(() -> namespace).get(); - FutureUtils.result(store.init(spec)); - - doSetup(); - } - - protected abstract void doSetup() throws Exception; - - @After - public void tearDown() throws Exception { - doTeardown(); - - store.close(); - - if (null != scheduler) { - scheduler.shutdown(); - } - } - - protected abstract void doTeardown() throws Exception; - -} diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCStoreFactoryImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCStoreFactoryImplTest.java deleted file mode 100644 index 89095de1e44..00000000000 --- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/store/MVCCStoreFactoryImplTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.stream.storage.impl.store; - -import static org.apache.bookkeeper.statelib.impl.mvcc.MVCCUtils.NOP_CMD; -import static org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactoryImpl.normalizedName; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.time.Duration; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.coder.ByteArrayCoder; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore; -import org.apache.bookkeeper.statelib.impl.rocksdb.checkpoint.fs.FSCheckpointManager; -import org.apache.bookkeeper.stream.storage.StorageResources; -import org.apache.bookkeeper.stream.storage.StorageResourcesSpec; -import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.distributedlog.DLSN; -import org.apache.distributedlog.LogRecord; -import org.apache.distributedlog.LogRecordWithDLSN; -import org.apache.distributedlog.api.AsyncLogReader; -import org.apache.distributedlog.api.AsyncLogWriter; -import org.apache.distributedlog.api.DistributedLogManager; -import org.apache.distributedlog.api.namespace.Namespace; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test of {@link MVCCStoreFactoryImpl}. - */ -@Slf4j -public class MVCCStoreFactoryImplTest { - - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - - private Namespace namespace; - private File[] storeDirs; - private StorageResources resources; - private MVCCStoreFactoryImpl factory; - - private final CompositeConfiguration compConf = - new CompositeConfiguration(); - private final StorageConfiguration storageConf = - new StorageConfiguration(compConf); - - @Before - public void setup() throws IOException { - this.namespace = mock(Namespace.class); - - DistributedLogManager dlm = mock(DistributedLogManager.class); - when(dlm.asyncClose()).thenReturn(FutureUtils.Void()); - when(namespace.openLog(anyString())).thenReturn(dlm); - AsyncLogWriter logWriter = mock(AsyncLogWriter.class); - when(dlm.openAsyncLogWriter()).thenReturn(FutureUtils.value(logWriter)); - when(dlm.openAsyncLogWriter(any())).thenReturn(FutureUtils.value(logWriter)); - when(logWriter.getLastTxId()).thenReturn(-1L); - DLSN dlsn = new DLSN(0L, 0L, 0L); - when(logWriter.write(any(LogRecord.class))).thenReturn(FutureUtils.value(dlsn)); - when(logWriter.asyncClose()).thenReturn(FutureUtils.Void()); - AsyncLogReader logReader = mock(AsyncLogReader.class); - when(dlm.openAsyncLogReader(anyLong())).thenReturn(FutureUtils.value(logReader)); - when(logReader.asyncClose()).thenReturn(FutureUtils.Void()); - LogRecordWithDLSN record = new LogRecordWithDLSN( - dlsn, 0L, NOP_CMD.toByteArray(), 0L); - when(logReader.readNext()).thenReturn(FutureUtils.value(record)); - - int numDirs = 3; - this.storeDirs = new File[numDirs]; - for (int i = 0; i < numDirs; i++) { - storeDirs[i] = testDir.newFolder("test-" + i); - } - - this.resources = StorageResources.create( - StorageResourcesSpec.builder() - .numCheckpointThreads(3) - .numIOReadThreads(3) - .numIOWriteThreads(3) - .build()); - this.factory = new MVCCStoreFactoryImpl( - () -> namespace, - () -> new FSCheckpointManager(new File(storeDirs[0], "checkpoints")), - storeDirs, - resources, - false, storageConf); - } - - @Test - public void testOpenStore() throws Exception { - long scId = System.currentTimeMillis(); - long streamId = scId + 1; - long rangeId = streamId + 1; - - try (MVCCAsyncStore store = FutureUtils.result( - factory.openStore(scId, streamId, rangeId, 0))) { - - log.info("Open store (scId = {}, streamId = {}, rangeId = {}) to test", - scId, streamId, rangeId); - - String storeName = String.format( - "%s/%s/%s", - normalizedName(scId), - normalizedName(streamId), - normalizedName(rangeId)); - assertEquals(storeName, store.name()); - - File localStoreDir = Paths.get( - storeDirs[(int) (streamId % storeDirs.length)].getAbsolutePath(), - "ranges", - normalizedName(scId), - normalizedName(streamId), - normalizedName(rangeId) - ).toFile(); - assertEquals(localStoreDir, store.spec().getLocalStateStoreDir()); - - String streamName = MVCCStoreFactoryImpl.streamName(scId, streamId, rangeId); - assertEquals(streamName, store.spec().getStream()); - - assertTrue(store.spec().getKeyCoder() instanceof ByteArrayCoder); - assertTrue(store.spec().getValCoder() instanceof ByteArrayCoder); - assertSame( - factory.writeIOScheduler().chooseThread(streamId), - store.spec().getWriteIOScheduler()); - assertSame( - factory.readIOScheduler().chooseThread(streamId), - store.spec().getReadIOScheduler()); - assertSame( - factory.checkpointScheduler().chooseThread(streamId), - store.spec().getCheckpointIOScheduler()); - assertTrue(store.spec().getCheckpointStore() instanceof FSCheckpointManager); - assertEquals(Duration.ofMinutes(15), store.spec().getCheckpointDuration()); - } - } - -} diff --git a/tests/backward-compat/bc-non-fips/src/test/java/org/apache/bookkeeper/tls/TestBCNonFips.java b/tests/backward-compat/bc-non-fips/src/test/java/org/apache/bookkeeper/tls/TestBCNonFips.java deleted file mode 100644 index 7fd2e7f75e9..00000000000 --- a/tests/backward-compat/bc-non-fips/src/test/java/org/apache/bookkeeper/tls/TestBCNonFips.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tls; - -import org.junit.Assert; -import org.junit.Test; - -/** - * Test Bouncy Castle Provider load non FIPS version. - */ -public class TestBCNonFips { - - /** - * Verify the BouncyCastleProvider Name is expected. - */ - @Test - public void testGetBouncyCastleProviderName() { - String bcName = TLSContextFactory.getProvider().getName(); - Assert.assertEquals(bcName, TLSContextFactory.BC); - } -} diff --git a/tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/integration/utils/MavenClassLoaderTest.java b/tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/integration/utils/MavenClassLoaderTest.java deleted file mode 100644 index a89be895bd0..00000000000 --- a/tests/integration-tests-utils/src/test/java/org/apache/bookkeeper/tests/integration/utils/MavenClassLoaderTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tests.integration.utils; - -import com.google.common.collect.Lists; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test of {@link MavenClassLoader}. - */ -public class MavenClassLoaderTest { - @Test(expected = ClassNotFoundException.class) - public void testLog4JReplacement() throws Exception { - MavenClassLoader.forBookKeeperVersion("4.0.0") - .newInstance("org.apache.log4j.Logger"); - } - - @Test - public void testNoZooKeeperInterference() throws Exception { - // Use KeeperException, because ZooKeeper needs a watcher which would be a pain to construct - Object o = MavenClassLoader.forBookKeeperVersion("4.0.0") - .newInstance("org.apache.zookeeper.KeeperException$NoNodeException"); - Assert.assertFalse(o.getClass().equals( - org.apache.zookeeper.KeeperException.NoNodeException.class)); - } - - @Test - public void testStaticMethod() throws Exception { - Object o = MavenClassLoader.forBookKeeperVersion("4.6.0").callStaticMethod( - "org.apache.bookkeeper.client.BKException", "create", Lists.newArrayList(-101)); - Assert.assertEquals(o.getClass().getName(), - "org.apache.bookkeeper.client.BKException$BKLedgerFencedException"); - } -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/BookKeeperClusterTestBase.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/BookKeeperClusterTestBase.java deleted file mode 100644 index b15e917e250..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/BookKeeperClusterTestBase.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.cluster; - -import com.google.common.base.Stopwatch; -import java.net.URI; -import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.DefaultBookieAddressResolver; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.MetadataClientDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.tests.integration.topologies.BKCluster; -import org.apache.bookkeeper.tests.integration.topologies.BKClusterSpec; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * A docker container based bookkeeper cluster test base, providing similar facility like the one in unit test. - */ -@Slf4j -public abstract class BookKeeperClusterTestBase { - - protected static BKCluster bkCluster; - protected static URI metadataServiceUri; - protected static MetadataClientDriver metadataClientDriver; - protected static ScheduledExecutorService executor; - protected static Random rand = new Random(); - - @BeforeClass - public static void setupCluster() throws Exception { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 8; i++) { - sb.append((char) (rand.nextInt(26) + 'a')); - } - BKClusterSpec spec = BKClusterSpec.builder() - .clusterName(sb.toString()) - .numBookies(0) - .build(); - - setupCluster(spec); - } - - protected static void setupCluster(BKClusterSpec spec) throws Exception { - log.info("Setting up cluster {} with {} bookies : extraServerComponents = {}", - spec.clusterName(), spec.numBookies(), spec.extraServerComponents()); - - bkCluster = BKCluster.forSpec(spec); - bkCluster.start(); - - log.info("Cluster {} is setup", spec.clusterName()); - - metadataServiceUri = URI.create(bkCluster.getExternalServiceUri()); - ClientConfiguration conf = new ClientConfiguration() - .setMetadataServiceUri(metadataServiceUri.toString()); - executor = Executors.newSingleThreadScheduledExecutor(); - metadataClientDriver = MetadataDrivers.getClientDriver(metadataServiceUri); - metadataClientDriver.initialize(conf, executor, NullStatsLogger.INSTANCE, Optional.empty()); - - log.info("Initialized metadata client driver : {}", metadataServiceUri); - } - - @AfterClass - public static void teardownCluster() { - if (null != metadataClientDriver) { - metadataClientDriver.close(); - } - if (null != executor) { - executor.shutdown(); - } - if (null != bkCluster) { - bkCluster.stop(); - } - } - - private static boolean findIfBookieRegistered(String bookieName) throws Exception { - DefaultBookieAddressResolver resolver = - new DefaultBookieAddressResolver(metadataClientDriver.getRegistrationClient()); - Set bookies = - FutureUtils.result(metadataClientDriver - .getRegistrationClient().getWritableBookies()).getValue(); - Optional registered = - bookies.stream().filter(addr -> resolver.resolve(addr).getHostName().equals(bookieName)).findFirst(); - return registered.isPresent(); - } - - protected static void waitUntilBookieUnregistered(String bookieName) throws Exception { - Stopwatch sw = Stopwatch.createStarted(); - while (findIfBookieRegistered(bookieName)) { - TimeUnit.MILLISECONDS.sleep(1000); - log.info("Bookie {} is still registered in cluster {} after {} ms elapsed", - bookieName, bkCluster.getClusterName(), sw.elapsed(TimeUnit.MILLISECONDS)); - } - } - -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/SimpleClusterTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/SimpleClusterTest.java deleted file mode 100644 index 0f79cbc8dd0..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/cluster/SimpleClusterTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.cluster; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.util.Set; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tests.containers.BookieContainer; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runners.MethodSorters; - -/** - * A simple test on bookkeeper cluster operations, e.g. start bookies, stop bookies and list bookies. - */ -@Slf4j -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class SimpleClusterTest extends BookKeeperClusterTestBase { - - @Test - public void test000_ClusterIsEmpty() throws Exception { - Set bookies = - FutureUtils.result(metadataClientDriver.getRegistrationClient().getWritableBookies()).getValue(); - assertTrue(bookies.isEmpty()); - } - - @Test - public void test001_StartBookie() throws Exception { - String bookieName = "bookie-000"; - BookieContainer container = bkCluster.createBookie(bookieName); - assertNotNull("Container should be started", container); - assertEquals(1, bkCluster.getBookieContainers().size()); - assertSame(container, bkCluster.getBookie(bookieName)); - - Set bookies = - FutureUtils.result(metadataClientDriver.getRegistrationClient().getWritableBookies()).getValue(); - assertEquals(1, bookies.size()); - } - - @Test - public void test002_StopBookie() throws Exception { - String bookieName = "bookie-000"; - BookieContainer container = bkCluster.killBookie(bookieName); - assertNotNull("Bookie '" + bookieName + "' doesn't exist", container); - assertEquals(0, bkCluster.getBookieContainers().size()); - assertNull(bkCluster.getBookie(bookieName)); - - waitUntilBookieUnregistered(bookieName); - - Set bookies = - FutureUtils.result(metadataClientDriver.getRegistrationClient().getWritableBookies()).getValue(); - assertEquals(0, bookies.size()); - } - -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/BkCtlTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/BkCtlTest.java deleted file mode 100644 index 6067776492b..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/BkCtlTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tests.integration.stream; - -import static org.junit.Assert.assertTrue; - -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.tests.containers.BookieContainer; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.testcontainers.containers.Container.ExecResult; - -/** - * Integration test for `bkctl`. - */ -@Slf4j -public class BkCtlTest extends StreamClusterTestBase { - - @Rule - public final TestName testName = new TestName(); - - // - // `bookies` commands - // - - @Test - public void listBookies() throws Exception { - BookieContainer bookie = bkCluster.getAnyBookie(); - ExecResult result = bookie.execCmd( - BKCTL, - "bookies", - "list" - ); - String output = result.getStdout(); - assertTrue(output.contains("ReadWrite Bookies :")); - } - - // - // `bookie` commands - // - - @Test - public void showLastMark() throws Exception { - BookieContainer bookie = bkCluster.getAnyBookie(); - ExecResult result = bookie.execCmd( - BKCTL, - "bookie", - "lastmark" - ); - assertTrue(result.getStdout().contains("LastLogMark : Journal")); - } - - // - // `ledger` commands - // - - @Test - public void simpleTest() throws Exception { - ExecResult result = bkCluster.getAnyBookie().execCmd( - BKCTL, - "ledger", - "simpletest", - "--ensemble-size", "3", - "--write-quorum-size", "3", - "--ack-quorum-size", "2", - "--num-entries", "100" - ); - assertTrue( - result.getStdout().contains("100 entries written to ledger")); - } - - // - // `namespace` commands - // - - @Test - public void createNamespace() throws Exception { - String nsName = testName.getMethodName(); - ExecResult result = bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "namespace", - "create", - nsName - ); - assertTrue( - result.getStdout().contains("Successfully created namespace '" + nsName + "'")); - } - - // - // `tables` commands - // - - @Test - public void createTable() throws Exception { - String tableName = testName.getMethodName(); - ExecResult result = bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "tables", - "create", - tableName - ); - assertTrue( - result.getStdout().contains("Successfully created table '" + tableName + "'")); - } - - // - // `table` commands - // - - @Test - public void putGetKey() throws Exception { - String key = testName.getMethodName() + "-key"; - String value = testName.getMethodName() + "-value"; - ExecResult result = bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "table", - "put", - TEST_TABLE, - key, - value - ); - assertTrue( - result.getStdout().contains(String.format("Successfully update kv: ('%s', '%s')", - key, value - ))); - - result = bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "table", - "get", - TEST_TABLE, - key); - assertTrue( - result.getStdout().contains(String.format("value = %s", value))); - } - - @Test - public void incGetKey() throws Exception { - String key = testName.getMethodName() + "-key"; - long value = System.currentTimeMillis(); - ExecResult result = bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "table", - "inc", - TEST_TABLE, - key, - "" + value - ); - assertTrue( - result.getStdout().contains(String.format("Successfully increment kv: ('%s', amount = '%s').", - key, value - ))); - - result = bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "table", - "get", - TEST_TABLE, - key); - assertTrue( - result.getStdout().contains(String.format("value = %s", value))); - } - -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/LocationClientTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/LocationClientTest.java deleted file mode 100644 index d231ce9d83a..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/LocationClientTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.stream; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.clients.impl.internal.LocationClientImpl; -import org.apache.bookkeeper.clients.impl.internal.api.LocationClient; -import org.apache.bookkeeper.common.util.OrderedScheduler; -import org.apache.bookkeeper.common.util.Revisioned; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Integration test for location test. - */ -@Slf4j -public class LocationClientTest extends StreamClusterTestBase { - - private OrderedScheduler scheduler; - private LocationClient client; - - @Before - public void setup() { - scheduler = OrderedScheduler.newSchedulerBuilder() - .name("location-client-test") - .numThreads(1) - .build(); - client = new LocationClientImpl( - newStorageClientSettings(), - scheduler); - } - - @After - public void teardown() { - if (null != client) { - client.close(); - } - if (null != scheduler) { - scheduler.shutdown(); - } - } - - @Test - public void testLocateStorageContainers() throws Exception { - List responses = client.locateStorageContainers( - Lists.newArrayList( - Revisioned.of(ROOT_STORAGE_CONTAINER_ID, -1L)) - ).get(); - assertEquals(1, responses.size()); - OneStorageContainerEndpointResponse oneResponse = responses.get(0); - assertEquals(StatusCode.SUCCESS, oneResponse.getStatusCode()); - - Endpoint endpoint = oneResponse.getEndpoint().getRwEndpoint(); - log.info("Current cluster endpoints = {}", getInternalStreamEndpoints()); - log.info("Response : rw endpoint = {}", endpoint); - assertTrue(getInternalStreamEndpoints().contains(endpoint)); - - assertEquals(1, oneResponse.getEndpoint().getRoEndpointCount()); - endpoint = oneResponse.getEndpoint().getRoEndpoint(0); - log.info("Response : ro endpoint = {}", endpoint); - assertTrue(getInternalStreamEndpoints().contains(endpoint)); - } - - -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java deleted file mode 100644 index e897564d05c..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.stream; - -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.apache.bookkeeper.clients.admin.StorageAdminClient; -import org.apache.bookkeeper.clients.exceptions.ClientException; -import org.apache.bookkeeper.clients.exceptions.NamespaceExistsException; -import org.apache.bookkeeper.clients.exceptions.NamespaceNotFoundException; -import org.apache.bookkeeper.clients.exceptions.StreamExistsException; -import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.apache.bookkeeper.stream.proto.storage.StatusCode; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Integration test for stream admin client test. - */ -public class StorageAdminClientTest extends StreamClusterTestBase { - - @Rule - public final TestName testName = new TestName(); - - @Test - public void testNamespaceAPIClientSideRouting() throws Exception { - testNamespaceAPI(false); - } - - @Test - public void testNamespaceAPIServerSideRouting() throws Exception { - testNamespaceAPI(true); - } - - private void testNamespaceAPI(boolean enableServerSideRouting) throws Exception { - try (StorageAdminClient adminClient = - createStorageAdminClient(newStorageClientSettings(enableServerSideRouting))) { - testNamespaceAPI(adminClient); - } - } - - private void testNamespaceAPI(StorageAdminClient adminClient) throws Exception { - // Create a namespace - String nsName = testName.getMethodName(); - NamespaceConfiguration colConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - NamespaceProperties colProps = FutureUtils.result(adminClient.createNamespace(nsName, colConf)); - assertEquals(nsName, colProps.getNamespaceName()); - assertEquals(colConf.getDefaultStreamConf(), colProps.getDefaultStreamConf()); - - // create a duplicated namespace - try { - FutureUtils.result(adminClient.createNamespace(nsName, colConf)); - fail("Should fail on creation if namespace " + nsName + " already exists"); - } catch (NamespaceExistsException cee) { - // expected - } catch (ClientException ce) { - // TODO: currently range server throws InternalServerError - assertTrue(ce.getMessage().endsWith("code = " + StatusCode.INTERNAL_SERVER_ERROR)); - } - - String notFoundColName = testName.getMethodName() + "_notfound"; - // get a not-found namespace - try { - FutureUtils.result(adminClient.getNamespace(notFoundColName)); - fail("Should fail on get if namespace " + notFoundColName + " doesn't exist"); - } catch (NamespaceNotFoundException cnfe) { - // expected - } - - // delete a not-found namespace - try { - FutureUtils.result(adminClient.deleteNamespace(notFoundColName)); - fail("Should fail on delete if namespace " + notFoundColName + " doesn't exist"); - } catch (NamespaceNotFoundException cnfe) { - // expected - } - - // get an existing namespace - NamespaceProperties getColProps = FutureUtils.result(adminClient.getNamespace(nsName)); - assertEquals(colProps, getColProps); - - // delete an existing namespace - Boolean deleted = FutureUtils.result(adminClient.deleteNamespace(nsName)); - assertTrue(deleted); - - // the namespace should not exist after deleted. - try { - FutureUtils.result(adminClient.getNamespace(nsName)); - fail("Should fail on get if namespace " + nsName + " doesn't exist"); - } catch (NamespaceNotFoundException cnfe) { - // expected - } - } - - @Test - public void testStreamAPIClientSideRouting() throws Exception { - testStreamAPI(false); - } - - @Test - public void testStreamAPIServerSideRouting() throws Exception { - testStreamAPI(false); - } - - private void testStreamAPI(boolean enableServerSideRouting) throws Exception { - try (StorageAdminClient adminClient = - createStorageAdminClient(newStorageClientSettings(enableServerSideRouting))) { - testStreamAPI(adminClient); - } - } - - private void testStreamAPI(StorageAdminClient adminClient) throws Exception { - // Create a namespace - String nsName = testName.getMethodName() + "_ns"; - NamespaceConfiguration colConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - NamespaceProperties colProps = FutureUtils.result(adminClient.createNamespace(nsName, colConf)); - assertEquals(nsName, colProps.getNamespaceName()); - assertEquals(colConf.getDefaultStreamConf(), colProps.getDefaultStreamConf()); - - // Create a stream - String streamName = testName.getMethodName() + "_stream"; - StreamConfiguration streamConf = StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .build(); - StreamProperties streamProps = FutureUtils.result(adminClient.createStream(nsName, streamName, streamConf)); - assertEquals(streamName, streamProps.getStreamName()); - - // create a duplicated stream - try { - FutureUtils.result(adminClient.createStream(nsName, streamName, streamConf)); - fail("Should fail on creation if stream " + streamName + " already exists"); - } catch (StreamExistsException cee) { - // expected - } catch (ClientException ce) { - // TODO: currently it throws InternalServerError for stream exists case - assertTrue(ce.getMessage().endsWith("code = " + StatusCode.INTERNAL_SERVER_ERROR)); - } - - String notFoundStreamName = testName.getMethodName() + "_notfound"; - // get a not-found stream - try { - FutureUtils.result(adminClient.getStream(nsName, notFoundStreamName)); - fail("Should fail on get if stream " + notFoundStreamName + " doesn't exist"); - } catch (StreamNotFoundException cnfe) { - // expected - } - - // delete a not-found stream - try { - FutureUtils.result(adminClient.deleteStream(nsName, notFoundStreamName)); - fail("Should fail on delete if stream " + notFoundStreamName + " doesn't exist"); - } catch (StreamNotFoundException cnfe) { - // expected - } - - // get an existing stream - StreamProperties getStreamProps = FutureUtils.result(adminClient.getStream(nsName, streamName)); - assertEquals(streamProps, getStreamProps); - - // delete an existing stream - Boolean deleted = FutureUtils.result(adminClient.deleteStream(nsName, streamName)); - assertTrue(deleted); - - // the stream should not exist after deleted. - try { - FutureUtils.result(adminClient.getStream(nsName, streamName)); - fail("Should fail on get if stream " + nsName + " doesn't exist"); - } catch (StreamNotFoundException cnfe) { - // expected - } - } -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java deleted file mode 100644 index 04a91a4b496..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.stream; - -import java.util.List; -import java.util.Random; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.api.StorageClient; -import org.apache.bookkeeper.clients.StorageClientBuilder; -import org.apache.bookkeeper.clients.admin.StorageAdminClient; -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.apache.bookkeeper.clients.utils.NetUtils; -import org.apache.bookkeeper.stream.proto.common.Endpoint; -import org.apache.bookkeeper.tests.integration.cluster.BookKeeperClusterTestBase; -import org.apache.bookkeeper.tests.integration.topologies.BKClusterSpec; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * Similar as {@link org.apache.bookkeeper.tests.integration.cluster.BookKeeperClusterTestBase}, - * but enabled stream storage for testing stream storage related features. - */ -@Slf4j -public abstract class StreamClusterTestBase extends BookKeeperClusterTestBase { - - protected static Random rand = new Random(); - protected static final String BKCTL = "/opt/bookkeeper/bin/bkctl"; - protected static final String STREAM_URI = "--service-uri bk://localhost:4181"; - protected static final String TEST_TABLE = "test-table"; - - @BeforeClass - public static void setupCluster() throws Exception { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 8; i++) { - sb.append((char) (rand.nextInt(26) + 'a')); - } - BKClusterSpec spec = BKClusterSpec.builder() - .clusterName(sb.toString()) - .numBookies(3) - .extraServerComponents("org.apache.bookkeeper.stream.server.StreamStorageLifecycleComponent") - .build(); - BookKeeperClusterTestBase.setupCluster(spec); - bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "namespace", - "create", - "default"); - bkCluster.getAnyBookie().execCmd( - BKCTL, - STREAM_URI, - "tables", - "create", - TEST_TABLE); - } - - @AfterClass - public static void teardownCluster() { - BookKeeperClusterTestBase.teardownCluster(); - } - - protected static int getNumBookies() { - return bkCluster.getBookieContainers().size(); - } - - protected static List getExsternalStreamEndpoints() { - return bkCluster.getBookieContainers().values().stream() - .map(container -> - NetUtils.parseEndpoint(container.getExternalGrpcEndpointStr())) - .collect(Collectors.toList()); - } - - protected static List getInternalStreamEndpoints() { - return bkCluster.getBookieContainers().values().stream() - .map(container -> - NetUtils.parseEndpoint(container.getInternalGrpcEndpointStr())) - .collect(Collectors.toList()); - } - - // - // Test Util Methods - // - - protected static StorageClientSettings newStorageClientSettings() { - return newStorageClientSettings(false); - } - - protected static StorageClientSettings newStorageClientSettings(boolean enableServerSideRouting) { - String serviceUri = String.format( - "bk://%s/", - getExsternalStreamEndpoints().stream() - .map(endpoint -> NetUtils.endpointToString(endpoint)) - .collect(Collectors.joining(","))); - return StorageClientSettings.newBuilder() - .serviceUri(serviceUri) - .endpointResolver(endpoint -> { - String internalEndpointStr = NetUtils.endpointToString(endpoint); - String externalEndpointStr = - bkCluster.resolveExternalGrpcEndpointStr(internalEndpointStr); - log.info("Resolve endpoint {} to {}", internalEndpointStr, externalEndpointStr); - return NetUtils.parseEndpoint(externalEndpointStr); - }) - .usePlaintext(true) - .enableServerSideRouting(enableServerSideRouting) - .build(); - } - - protected static StorageAdminClient createStorageAdminClient(StorageClientSettings settings) { - return StorageClientBuilder.newBuilder() - .withSettings(settings) - .buildAdmin(); - } - - protected static StorageClient createStorageClient(StorageClientSettings settings, String namespace) { - return StorageClientBuilder.newBuilder() - .withSettings(settings) - .withNamespace(namespace) - .build(); - } - -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java deleted file mode 100644 index 630c13a5233..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tests.integration.stream; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.api.StorageClient; -import org.apache.bookkeeper.api.kv.PTable; -import org.apache.bookkeeper.api.kv.exceptions.KvApiException; -import org.apache.bookkeeper.api.kv.result.Code; -import org.apache.bookkeeper.api.kv.result.KeyValue; -import org.apache.bookkeeper.clients.admin.StorageAdminClient; -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.apache.bookkeeper.common.testing.annotations.FlakyTest; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.StorageType; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TestName; - -/** - * Integration test for table service. - */ -@Slf4j -public class TableClientSimpleTest extends StreamClusterTestBase { - - @Rule - public final TestName testName = new TestName(); - - private final String namespace = "test_namespace"; - private StorageAdminClient adminClient; - private StorageClient storageClient; - - @Before - public void setup() { - StorageClientSettings settings = newStorageClientSettings(); - String namespace = "test_namespace"; - adminClient = createStorageAdminClient(settings); - storageClient = createStorageClient(settings, namespace); - } - - @After - public void teardown() { - if (null != adminClient) { - adminClient.close(); - } - if (null != storageClient) { - storageClient.close(); - } - } - - private static ByteBuf getLKey(int i) { - return Unpooled.wrappedBuffer(String.format("test-lkey-%06d", i).getBytes(UTF_8)); - } - - private static ByteBuf getValue(int i) { - return Unpooled.wrappedBuffer(String.format("test-val-%06d", i).getBytes(UTF_8)); - } - - @FlakyTest("https://github.com/apache/bookkeeper/issues/1440") - public void testTableSimpleAPI() throws Exception { - // Create a namespace - NamespaceConfiguration nsConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - NamespaceProperties nsProps = result(adminClient.createNamespace(namespace, nsConf)); - assertEquals(namespace, nsProps.getNamespaceName()); - assertEquals(nsConf.getDefaultStreamConf(), nsProps.getDefaultStreamConf()); - - // Create a stream - String streamName = testName.getMethodName() + "_stream"; - StreamConfiguration streamConf = StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build(); - StreamProperties streamProps = result( - adminClient.createStream(namespace, streamName, streamConf)); - assertEquals(streamName, streamProps.getStreamName()); - - // Open the table - PTable table = result(storageClient.openPTable(streamName)); - byte[] rKey = "routing-key".getBytes(UTF_8); - byte[] lKey = "testing-key".getBytes(UTF_8); - byte[] value1 = "testing-value-1".getBytes(UTF_8); - byte[] value2 = "testing-value-2".getBytes(UTF_8); - - // put first key - ByteBuf rKeyBuf = Unpooled.wrappedBuffer(rKey); - ByteBuf lKeyBuf = Unpooled.wrappedBuffer(lKey); - ByteBuf valBuf1 = Unpooled.wrappedBuffer(value1); - ByteBuf valBuf2 = Unpooled.wrappedBuffer(value2); - - // normal put - assertNull(result( - table.put(rKeyBuf, lKeyBuf, valBuf1))); - - // putIfAbsent failure - assertArrayEquals( - value1, - ByteBufUtil.getBytes(result(table.putIfAbsent(rKeyBuf, lKeyBuf, valBuf2)))); - - // delete failure - assertFalse( - result(table.delete(rKeyBuf, lKeyBuf, valBuf2))); - - // delete success - assertTrue( - result(table.delete(rKeyBuf, lKeyBuf, valBuf1))); - - // get - assertNull( - result(table.get(rKeyBuf, lKeyBuf))); - - // putIfAbsent success - assertNull( - result(table.putIfAbsent(rKeyBuf, lKeyBuf, valBuf2))); - - // get returns val2 - assertArrayEquals( - value2, - ByteBufUtil.getBytes(result(table.get(rKeyBuf, lKeyBuf)))); - - // vPut failure - try { - result( - table.vPut(rKeyBuf, lKeyBuf, valBuf1, 9999L)); - fail("Should fail vPut if the version doesn't match"); - } catch (KvApiException e) { - assertEquals(Code.BAD_REVISION, e.getCode()); - } - - // vPut success - assertEquals( - 1L, - result( - table.vPut(rKeyBuf, lKeyBuf, valBuf1, 0L)).longValue()); - - // vDelete failure - try { - result( - table.vDelete(rKeyBuf, lKeyBuf, 9999L)); - fail("Should fail vDelete if the version doesn't match"); - } catch (KvApiException e) { - assertEquals(Code.BAD_REVISION, e.getCode()); - } - - // vDelete success - try (KeyValue prevKv = result( - table.vDelete(rKeyBuf, lKeyBuf, 1L))) { - assertNotNull(prevKv); - assertEquals(1L, prevKv.version()); - assertArrayEquals( - value1, - ByteBufUtil.getBytes(prevKv.value())); - } - - // write a range of key - int numKvs = 100; - rKeyBuf = Unpooled.wrappedBuffer("test-key".getBytes(UTF_8)); - for (int i = 0; i < numKvs; i++) { - lKeyBuf = getLKey(i); - valBuf1 = getValue(i); - result(table.put(rKeyBuf, lKeyBuf, valBuf1)); - } - - // get ranges - ByteBuf lStartKey = getLKey(20); - ByteBuf lEndKey = getLKey(50); - List> kvs = result( - table.range(rKeyBuf, lStartKey, lEndKey)); - assertEquals(31, kvs.size()); - int i = 20; - for (KeyValue kvPair : kvs) { - assertEquals(getLKey(i), kvPair.key()); - assertEquals(getValue(i), kvPair.value()); - ++i; - kvPair.close(); - } - assertEquals(51, i); - - // delete range - kvs = result( - table.deleteRange(rKeyBuf, lStartKey, lEndKey)); - assertEquals(31, kvs.size()); - i = 20; - for (KeyValue kvPair : kvs) { - assertEquals(getLKey(i), kvPair.key()); - assertEquals(getValue(i), kvPair.value()); - ++i; - kvPair.close(); - } - assertEquals(51, i); - - // get ranges again - kvs = result(table.range(rKeyBuf, lStartKey, lEndKey)); - assertTrue(kvs.isEmpty()); - - byte[] lIncrKey = "test-incr-lkey".getBytes(UTF_8); - ByteBuf lIncrKeyBuf = Unpooled.wrappedBuffer(lIncrKey); - - // test increment - for (int j = 0; j < 5; j++) { - result(table.increment(rKeyBuf, lIncrKeyBuf, 100L)); - long number = result(table.getNumber(rKeyBuf, lIncrKeyBuf)); - assertEquals(100L * (j + 1), number); - } - - for (int j = 5; j < 10; j++) { - long number = result(table.incrementAndGet(rKeyBuf, lIncrKeyBuf, 100L)); - assertEquals(100L * (j + 1), number); - } - } - - public void testTableTtl() throws Exception { - final String ns = namespace + "_ttl"; - final int ttlSeconds = 5; - - result(adminClient.createNamespace(ns, NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build())); - - final String streamName = testName.getMethodName() + "_stream"; - result(adminClient.createStream(ns, streamName, StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .setTtlSeconds(ttlSeconds) - .build())); - - final PTable table = result(storageClient.openPTable(streamName)); - - // put first key - final byte[] rKey = "rKey".getBytes(UTF_8); - final byte[] lKey = "lKey".getBytes(UTF_8); - final byte[] val = "val".getBytes(UTF_8); - - final ByteBuf rKeyBuf = Unpooled.wrappedBuffer(rKey); - final ByteBuf lKeyBuf = Unpooled.wrappedBuffer(lKey); - final ByteBuf valBuf = Unpooled.wrappedBuffer(val); - - result(table.put(rKeyBuf, lKeyBuf, valBuf)); - - // Ensure we can read the value back. this may be flaky if the test gets suspended for too long. - assertArrayEquals(val, ByteBufUtil.getBytes(result(table.get(rKeyBuf, lKeyBuf)))); - - // Wait for the value to expire, and ensure we can't read it. - Thread.sleep(ttlSeconds + 1); - assertNull(ByteBufUtil.getBytes(result(table.get(rKeyBuf, lKeyBuf)))); - } -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java deleted file mode 100644 index 81c3c853109..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tests.integration.stream; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import java.util.concurrent.CompletableFuture; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.api.StorageClient; -import org.apache.bookkeeper.api.kv.PTable; -import org.apache.bookkeeper.api.kv.Txn; -import org.apache.bookkeeper.api.kv.impl.options.OptionFactoryImpl; -import org.apache.bookkeeper.api.kv.op.CompareResult; -import org.apache.bookkeeper.api.kv.op.OpType; -import org.apache.bookkeeper.api.kv.options.DeleteOption; -import org.apache.bookkeeper.api.kv.options.OptionFactory; -import org.apache.bookkeeper.api.kv.options.Options; -import org.apache.bookkeeper.api.kv.options.PutOption; -import org.apache.bookkeeper.api.kv.options.RangeOption; -import org.apache.bookkeeper.api.kv.result.DeleteResult; -import org.apache.bookkeeper.api.kv.result.KeyValue; -import org.apache.bookkeeper.api.kv.result.PutResult; -import org.apache.bookkeeper.api.kv.result.RangeResult; -import org.apache.bookkeeper.api.kv.result.Result; -import org.apache.bookkeeper.api.kv.result.TxnResult; -import org.apache.bookkeeper.clients.admin.StorageAdminClient; -import org.apache.bookkeeper.clients.config.StorageClientSettings; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.stream.proto.NamespaceConfiguration; -import org.apache.bookkeeper.stream.proto.NamespaceProperties; -import org.apache.bookkeeper.stream.proto.StorageType; -import org.apache.bookkeeper.stream.proto.StreamConfiguration; -import org.apache.bookkeeper.stream.proto.StreamProperties; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Integration test for table service. - */ -@Slf4j -public class TableClientTest extends StreamClusterTestBase { - - @Rule - public final TestName testName = new TestName(); - - private final OptionFactory optionFactory = new OptionFactoryImpl<>(); - - private static ByteBuf getLKey(int i) { - return Unpooled.wrappedBuffer(String.format("test-lkey-%06d", i).getBytes(UTF_8)); - } - - private static ByteBuf getValue(int i) { - return Unpooled.wrappedBuffer(String.format("test-val-%06d", i).getBytes(UTF_8)); - } - - @Test - public void testTableAPIClientSideRouting() throws Exception { - testTableAPI(false); - } - - @Test - public void testTableAPIServerSideRouting() throws Exception { - testTableAPI(true); - } - - private void testTableAPI(boolean enableServerSideRouting) throws Exception { - StorageClientSettings setting = newStorageClientSettings(enableServerSideRouting); - try (StorageAdminClient adminClient = createStorageAdminClient(setting)) { - final String namespace = testName.getMethodName(); - try (StorageClient storageClient = createStorageClient(setting, namespace)) { - testTableAPI(namespace, adminClient, storageClient); - } - } - } - - private void testTableAPI(String namespace, - StorageAdminClient adminClient, - StorageClient storageClient) throws Exception { - // Create a namespace - NamespaceConfiguration nsConf = NamespaceConfiguration.newBuilder() - .setDefaultStreamConf(DEFAULT_STREAM_CONF) - .build(); - NamespaceProperties nsProps = FutureUtils.result(adminClient.createNamespace(namespace, nsConf)); - assertEquals(namespace, nsProps.getNamespaceName()); - assertEquals(nsConf.getDefaultStreamConf(), nsProps.getDefaultStreamConf()); - - // Create a stream - String streamName = testName.getMethodName() + "_stream"; - StreamConfiguration streamConf = StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF) - .setStorageType(StorageType.TABLE) - .build(); - StreamProperties streamProps = FutureUtils.result( - adminClient.createStream(namespace, streamName, streamConf)); - assertEquals(streamName, streamProps.getStreamName()); - - // Open the table - PTable table = FutureUtils.result(storageClient.openPTable(streamName)); - byte[] rKey = "routing-key".getBytes(UTF_8); - byte[] lKey = "testing-key".getBytes(UTF_8); - byte[] value = "testing-value".getBytes(UTF_8); - - // put first key - ByteBuf rKeyBuf = Unpooled.wrappedBuffer(rKey); - ByteBuf lKeyBuf = Unpooled.wrappedBuffer(lKey); - ByteBuf valBuf = Unpooled.wrappedBuffer(value); - - try (PutOption option = Options.putAndGet()) { - try (PutResult putResult = FutureUtils.result(table.put( - rKeyBuf, - lKeyBuf, - valBuf, - option))) { - assertNull(putResult.prevKv()); - } - } - - // put second key - ByteBuf valBuf2 = Unpooled.wrappedBuffer("testing-value-2".getBytes(UTF_8)); - try (PutOption option = Options.putAndGet()) { - try (PutResult putResult = FutureUtils.result(table.put( - rKeyBuf, - lKeyBuf, - valBuf2, - option))) { - assertNotNull(putResult.prevKv()); - KeyValue prevKv = putResult.prevKv(); - assertEquals("testing-key", new String(ByteBufUtil.getBytes(prevKv.key()), UTF_8)); - assertEquals("testing-value", new String(ByteBufUtil.getBytes(prevKv.value()), UTF_8)); - } - } - - // get key - try (RangeOption option = optionFactory.newRangeOption().build()) { - try (RangeResult getResult = FutureUtils.result(table.get( - rKeyBuf, - lKeyBuf, - option - ))) { - assertEquals(1, getResult.count()); - assertEquals(1, getResult.kvs().size()); - KeyValue kv = getResult.kvs().get(0); - assertEquals("testing-key", new String(ByteBufUtil.getBytes(kv.key()), UTF_8)); - assertEquals("testing-value-2", new String(ByteBufUtil.getBytes(kv.value()), UTF_8)); - } - } - - // delete key - try (DeleteOption option = optionFactory.newDeleteOption().prevKv(true).build()) { - try (DeleteResult deleteResult = FutureUtils.result(table.delete( - rKeyBuf, - lKeyBuf, - option))) { - assertEquals(1, deleteResult.numDeleted()); - assertEquals(1, deleteResult.prevKvs().size()); - KeyValue kv = deleteResult.prevKvs().get(0); - assertEquals("testing-key", new String(ByteBufUtil.getBytes(kv.key()), UTF_8)); - assertEquals("testing-value-2", new String(ByteBufUtil.getBytes(kv.value()), UTF_8)); - } - } - - // write a range of key - int numKvs = 100; - rKeyBuf = Unpooled.wrappedBuffer("test-key".getBytes(UTF_8)); - try (PutOption option = Options.blindPut()) { - for (int i = 0; i < numKvs; i++) { - lKeyBuf = getLKey(i); - valBuf = getValue(i); - FutureUtils.result(table.put( - rKeyBuf, - lKeyBuf, - valBuf, - option)); - } - } - - // get ranges - ByteBuf lStartKey = getLKey(20); - ByteBuf lEndKey = getLKey(50); - try (RangeOption option = optionFactory.newRangeOption().endKey(lEndKey).build()) { - try (RangeResult rangeResult = FutureUtils.result(table.get( - rKeyBuf, - lStartKey, - option))) { - assertEquals(31, rangeResult.kvs().size()); - assertEquals(31, rangeResult.count()); - int i = 20; - for (KeyValue kvPair : rangeResult.kvs()) { - assertEquals(getLKey(i), kvPair.key()); - assertEquals(getValue(i), kvPair.value()); - ++i; - } - assertEquals(51, i); - } - } - - // delete range - try (DeleteOption option = optionFactory.newDeleteOption() - .prevKv(true) - .endKey(lEndKey) - .build()) { - try (DeleteResult deleteRangeResult = FutureUtils.result(table.delete( - rKeyBuf, - lStartKey, - option))) { - assertEquals(31, deleteRangeResult.numDeleted()); - assertEquals(31, deleteRangeResult.prevKvs().size()); - int i = 20; - for (KeyValue kvPair : deleteRangeResult.prevKvs()) { - assertEquals(getLKey(i), kvPair.key()); - assertEquals(getValue(i), kvPair.value()); - ++i; - } - assertEquals(51, i); - - } - } - - // test txn - byte[] lTxnKey = "txn-key".getBytes(UTF_8); - ByteBuf lTxnKeyBuf = Unpooled.wrappedBuffer(lTxnKey); - byte[] txnValue = "txn-value".getBytes(UTF_8); - ByteBuf txnValueBuf = Unpooled.wrappedBuffer(txnValue); - Txn txn = table.txn(lTxnKeyBuf); - - CompletableFuture> commitFuture = txn - .If( - table.opFactory().compareValue(CompareResult.EQUAL, lTxnKeyBuf, Unpooled.wrappedBuffer(new byte[0])) - ) - .Then( - table.opFactory().newPut( - lTxnKeyBuf, txnValueBuf, table.opFactory().optionFactory().newPutOption().build())) - .commit(); - try (TxnResult txnResult = FutureUtils.result(commitFuture)) { - assertTrue(txnResult.isSuccess()); - assertEquals(1, txnResult.results().size()); - Result opResult = txnResult.results().get(0); - assertEquals(OpType.PUT, opResult.type()); - } - - // get key - try (RangeOption option = optionFactory.newRangeOption().build()) { - try (RangeResult getResult = FutureUtils.result(table.get( - lTxnKeyBuf, - lTxnKeyBuf, - option - ))) { - assertEquals(1, getResult.count()); - assertEquals(1, getResult.kvs().size()); - KeyValue kv = getResult.kvs().get(0); - assertEquals("txn-key", new String(ByteBufUtil.getBytes(kv.key()), UTF_8)); - assertEquals("txn-value", new String(ByteBufUtil.getBytes(kv.value()), UTF_8)); - } - } - - txn = table.txn(lTxnKeyBuf); - // txn failure - commitFuture = txn - .If( - table.opFactory().compareValue(CompareResult.EQUAL, lTxnKeyBuf, Unpooled.wrappedBuffer(new byte[0])) - ) - .Then( - table.opFactory().newPut( - lTxnKeyBuf, valBuf, table.opFactory().optionFactory().newPutOption().build())) - .commit(); - try (TxnResult txnResult = FutureUtils.result(commitFuture)) { - assertFalse(txnResult.isSuccess()); - assertEquals(0, txnResult.results().size()); - } - - } -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKCluster.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKCluster.java deleted file mode 100644 index 0d5b311a907..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKCluster.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.topologies; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.util.concurrent.UncheckedExecutionException; -import java.net.URI; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; -import org.apache.bookkeeper.stream.storage.impl.cluster.ZkClusterInitializer; -import org.apache.bookkeeper.tests.containers.BookieContainer; -import org.apache.bookkeeper.tests.containers.MetadataStoreContainer; -import org.apache.bookkeeper.tests.containers.ZKContainer; -import org.testcontainers.containers.Network; - -/** - * BookKeeper Cluster in containers. - */ -@Slf4j -public class BKCluster { - - /** - * BookKeeper Cluster Spec. - * - * @param spec bookkeeper cluster spec. - * @return the built bookkeeper cluster - */ - public static BKCluster forSpec(BKClusterSpec spec) { - return new BKCluster(spec); - } - - private final BKClusterSpec spec; - @Getter - private final String clusterName; - private final Network network; - private final MetadataStoreContainer metadataContainer; - private final Map bookieContainers; - private final Map internalEndpointsToExternalEndpoints; - private final int numBookies; - private final String extraServerComponents; - private volatile boolean enableContainerLog; - - private BKCluster(BKClusterSpec spec) { - this.spec = spec; - this.clusterName = spec.clusterName(); - this.network = Network.newNetwork(); - this.metadataContainer = (MetadataStoreContainer) new ZKContainer(clusterName) - .withNetwork(network) - .withNetworkAliases(ZKContainer.HOST_NAME); - this.bookieContainers = Maps.newTreeMap(); - this.internalEndpointsToExternalEndpoints = Maps.newConcurrentMap(); - this.numBookies = spec.numBookies(); - this.extraServerComponents = spec.extraServerComponents(); - this.enableContainerLog = spec.enableContainerLog(); - } - - public String getExternalServiceUri() { - return metadataContainer.getExternalServiceUri(); - } - - public String getInternalServiceUri() { - return metadataContainer.getInternalServiceUri(); - } - - public void start() throws Exception { - // start the metadata store - if (enableContainerLog) { - this.metadataContainer.tailContainerLog(); - } - this.metadataContainer.start(); - log.info("Successfully started metadata store container."); - - // init a new cluster - initNewCluster(metadataContainer.getExternalServiceUri()); - log.info("Successfully initialized metadata service uri : {}", - metadataContainer.getExternalServiceUri()); - - if (!Strings.isNullOrEmpty(extraServerComponents)) { - int numStorageContainers = numBookies > 0 ? 2 * numBookies : 8; - // initialize the stream storage. - new ZkClusterInitializer( - ZKMetadataDriverBase.getZKServersFromServiceUri(URI.create(metadataContainer.getExternalServiceUri())) - ).initializeCluster( - URI.create(metadataContainer.getInternalServiceUri()), - numStorageContainers); - log.info("Successfully initialized stream storage metadata with {} storage containers", - numStorageContainers); - } - - // create bookies - createBookies("bookie", numBookies); - } - - public String resolveExternalGrpcEndpointStr(String internalGrpcEndpointStr) { - String externalGrpcEndpointStr = internalEndpointsToExternalEndpoints.get(internalGrpcEndpointStr); - checkNotNull(externalGrpcEndpointStr, - "No internal grpc endpoint is found : " + internalGrpcEndpointStr); - return externalGrpcEndpointStr; - } - - public void stop() { - synchronized (this) { - bookieContainers.values().forEach(BookieContainer::stop); - } - - this.metadataContainer.stop(); - try { - this.network.close(); - } catch (Exception e) { - log.info("Failed to shutdown network for bookkeeper cluster {}", clusterName, e); - } - } - - protected void initNewCluster(String metadataServiceUri) throws Exception { - MetadataDrivers.runFunctionWithRegistrationManager( - new ServerConfiguration().setMetadataServiceUri(metadataServiceUri), - rm -> { - try { - rm.initNewCluster(); - } catch (Exception e) { - throw new UncheckedExecutionException("Failed to init a new cluster", e); - } - return null; - } - ); - } - - public synchronized Map getBookieContainers() { - return bookieContainers; - } - - - public synchronized BookieContainer getBookie(String bookieName) { - return bookieContainers.get(bookieName); - } - - public synchronized BookieContainer getAnyBookie() { - List bookieList = Lists.newArrayList(); - bookieList.addAll(bookieContainers.values()); - Collections.shuffle(bookieList); - checkArgument(!bookieList.isEmpty(), "No bookie is alive"); - return bookieList.get(0); - } - - public BookieContainer killBookie(String bookieName) { - BookieContainer container; - synchronized (this) { - container = bookieContainers.remove(bookieName); - if (null != container) { - internalEndpointsToExternalEndpoints.remove(container.getInternalGrpcEndpointStr()); - container.stop(); - } - } - return container; - } - - public BookieContainer createBookie(String bookieName) { - boolean shouldStart = false; - BookieContainer container; - synchronized (this) { - container = getBookie(bookieName); - if (null == container) { - shouldStart = true; - log.info("Creating bookie {}", bookieName); - container = (BookieContainer) new BookieContainer( - clusterName, bookieName, ZKContainer.SERVICE_URI, extraServerComponents - ).withNetwork(network).withNetworkAliases(bookieName); - if (enableContainerLog) { - container.tailContainerLog(); - } - bookieContainers.put(bookieName, container); - } - } - - if (shouldStart) { - log.info("Starting bookie {}", bookieName); - container.start(); - log.info("Started bookie {} : internal endpoint = {}, external endpoint = {}", - bookieName, container.getInternalGrpcEndpointStr(), container.getExternalGrpcEndpointStr()); - internalEndpointsToExternalEndpoints.put( - container.getInternalGrpcEndpointStr(), - container.getExternalGrpcEndpointStr()); - } - return container; - } - - public Map createBookies(String bookieNamePrefix, int numBookies) - throws Exception { - log.info("Creating {} bookies with bookie name prefix '{}'", numBookies, bookieNamePrefix); - List> startFutures = Lists.newArrayListWithExpectedSize(numBookies); - Map containers = Maps.newHashMap(); - for (int i = 0; i < numBookies; i++) { - final int idx = i; - startFutures.add( - CompletableFuture.runAsync(() -> { - String bookieName = String.format("%s-%03d", bookieNamePrefix, idx); - log.info("Starting bookie {} at cluster {}", bookieName, clusterName); - BookieContainer container = createBookie(bookieName); - synchronized (containers) { - containers.put(bookieName, container); - } - })); - } - FutureUtils.result(FutureUtils.collect(startFutures)); - return containers; - } -} diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKClusterSpec.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKClusterSpec.java deleted file mode 100644 index e919d1af8e6..00000000000 --- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/topologies/BKClusterSpec.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.topologies; - -import lombok.Builder; -import lombok.Builder.Default; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.Accessors; - -/** - * Spec to build {@link BKCluster}. - */ -@Builder -@Accessors(fluent = true) -@Getter -@Setter -public class BKClusterSpec { - - /** - * Returns the cluster name. - * - * @return the cluster name. - */ - String clusterName; - - /** - * Returns the number of bookies. - * - * @return the number of bookies; - */ - @Default - int numBookies = 0; - - /** - * Returns the extra server components. - * - * @return the extra server components. - */ - @Default - String extraServerComponents = ""; - - /** - * Returns the flag whether to enable/disable container log. - * - * @return the flag whether to enable/disable container log. - */ - @Default - boolean enableContainerLog = false; - -} diff --git a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/BookieShellTestBase.java b/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/BookieShellTestBase.java deleted file mode 100644 index 59626881da0..00000000000 --- a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/BookieShellTestBase.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration; - -import static org.junit.Assert.assertTrue; - -import lombok.extern.slf4j.Slf4j; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.Timeout; - -/** - * Test Base for testing bookie shell scripts. - */ -@Slf4j -public abstract class BookieShellTestBase { - @Rule - public Timeout testTimeout = Timeout.seconds(300); - - String currentVersion = System.getProperty("currentVersion"); - String bkScript; - - @Before - public void setup() { - bkScript = "/opt/bookkeeper/" + currentVersion + "/bin/bookkeeper"; - } - - @Test - public abstract void test000_Setup() throws Exception; - - @Test - public abstract void test999_Teardown(); - - protected abstract String runCommandInAnyContainer(String... cmd) throws Exception; - - @Test - public void test001_SimpleTest() throws Exception { - assertTrue(runCommandInAnyContainer( - bkScript, - "shell", - "simpletest", - "-ensemble", "3", - "-writeQuorum", "3", - "-ackQuorum", "2", - "-numEntries", "100" - ).contains("100 entries written to ledger")); - } - - @Test - public void test002_ListROBookies() throws Exception { - assertTrue(runCommandInAnyContainer( - bkScript, - "shell", - "listbookies", - "-ro" - ).contains("No bookie exists!")); - } - - @Test - public void test003_ListRWBookies() throws Exception { - assertTrue(runCommandInAnyContainer( - bkScript, - "shell", - "listbookies", - "-rw" - ).contains("ReadWrite Bookies :")); - } - -} diff --git a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestBookieShellCluster.java b/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestBookieShellCluster.java deleted file mode 100644 index 5de0437794e..00000000000 --- a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestBookieShellCluster.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertTrue; - -import com.github.dockerjava.api.DockerClient; -import java.util.concurrent.ExecutionException; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.api.BookKeeper; -import org.apache.bookkeeper.client.api.LedgerEntries; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.tests.integration.utils.BookKeeperClusterUtils; -import org.apache.bookkeeper.tests.integration.utils.DockerUtils; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.arquillian.test.api.ArquillianResource; -import org.junit.Assert; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; - -/** - * Test cluster related commands in bookie shell. - */ -@Slf4j -@RunWith(Arquillian.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestBookieShellCluster extends BookieShellTestBase { - - @ArquillianResource - private DockerClient docker; - - private String currentVersion = System.getProperty("currentVersion"); - - private static final byte[] PASSWORD = "foobar".getBytes(UTF_8); - - @Test - @Override - public void test000_Setup() throws Exception { - // First test to run, formats metadata and bookies - if (BookKeeperClusterUtils.metadataFormatIfNeeded(docker, currentVersion)) { - BookKeeperClusterUtils.formatAllBookies(docker, currentVersion); - } - assertTrue(BookKeeperClusterUtils.startAllBookiesWithVersion(docker, currentVersion)); - } - - @Test - @Override - public void test999_Teardown() { - assertTrue(BookKeeperClusterUtils.stopAllBookies(docker)); - } - - @Override - protected String runCommandInAnyContainer(String... cmds) throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - return DockerUtils.runCommand(docker, bookie, cmds); - } - - @Test - @Override - public void test001_SimpleTest() throws Exception { - super.test001_SimpleTest(); - } - - @Test - @Override - public void test002_ListROBookies() throws Exception { - super.test002_ListROBookies(); - } - - @Test - @Override - public void test003_ListRWBookies() throws Exception { - super.test003_ListRWBookies(); - } - - private static long writeNEntries(BookKeeper bk, int n, int numBookies) throws Exception { - try (WriteHandle writer = bk.newCreateLedgerOp().withEnsembleSize(numBookies) - .withWriteQuorumSize(numBookies).withAckQuorumSize(numBookies) - .withPassword(PASSWORD).execute().get()) { - int i = 0; - for (; i < n - 1; i++) { - writer.appendAsync(("entry" + i).getBytes(UTF_8)); - } - writer.append(("entry" + i).getBytes(UTF_8)); - - return writer.getId(); - } - } - - private static void validateNEntries(BookKeeper bk, long ledgerId, int n) throws Exception { - try (ReadHandle reader = bk.newOpenLedgerOp() - .withLedgerId(ledgerId) - .withPassword(PASSWORD) - .execute().get(); - LedgerEntries entries = reader.read(0, n - 1)) { - Assert.assertEquals(reader.getLastAddConfirmed(), n - 1); - - for (int i = 0; i < n; i++) { - Assert.assertEquals("entry" + i, new String(entries.getEntry(i).getEntryBytes(), UTF_8)); - } - } - } - - /** - * These tests on being able to access cluster internals, so can't be put in test base. - */ - @Test - public void test101_RegenerateIndex() throws Exception { - String zookeeper = String.format("zk+hierarchical://%s/ledgers", - BookKeeperClusterUtils.zookeeperConnectString(docker)); - int numEntries = 100; - - try (BookKeeper bk = BookKeeper.newBuilder( - new ClientConfiguration().setMetadataServiceUri(zookeeper)).build()) { - log.info("Writing entries"); - long ledgerId1 = writeNEntries(bk, numEntries, BookKeeperClusterUtils.allBookies().size()); - long ledgerId2 = writeNEntries(bk, numEntries, BookKeeperClusterUtils.allBookies().size()); - - log.info("Validate that we can read back"); - validateNEntries(bk, ledgerId1, numEntries); - validateNEntries(bk, ledgerId2, numEntries); - - String indexFileName1 = String.format("/opt/bookkeeper/data/ledgers/current/0/%d/%d.idx", - ledgerId1, ledgerId1); - String indexFileName2 = String.format("/opt/bookkeeper/data/ledgers/current/0/%d/%d.idx", - ledgerId2, ledgerId2); - - log.info("Stop bookies to flush, delete the index and start again"); - assertTrue(BookKeeperClusterUtils.stopAllBookies(docker)); - - BookKeeperClusterUtils.runOnAllBookies(docker, "rm", indexFileName1, indexFileName2); - assertTrue(BookKeeperClusterUtils.startAllBookiesWithVersion(docker, currentVersion)); - - log.info("Validate that we cannot read back"); - try { - validateNEntries(bk, ledgerId1, numEntries); - Assert.fail("Shouldn't have been able to find anything"); - } catch (BKException.BKNoSuchLedgerExistsException e) { - // expected - } - try { - validateNEntries(bk, ledgerId2, numEntries); - Assert.fail("Shouldn't have been able to find anything"); - } catch (BKException.BKNoSuchLedgerExistsException e) { - // expected - } - - assertTrue(BookKeeperClusterUtils.stopAllBookies(docker)); - - log.info("Regenerate the index file"); - BookKeeperClusterUtils.runOnAllBookies(docker, - bkScript, "shell", "regenerate-interleaved-storage-index-file", - "--ledgerIds", String.format("%d,%d", ledgerId1, ledgerId2), - "--password", new String(PASSWORD, UTF_8)); - assertTrue(BookKeeperClusterUtils.startAllBookiesWithVersion(docker, currentVersion)); - - log.info("Validate that we can read back, after regeneration"); - validateNEntries(bk, ledgerId1, numEntries); - validateNEntries(bk, ledgerId2, numEntries); - } - } - - @Test - public void test102_DumpRestoreMetadata() throws Exception { - String zookeeper = String.format("zk+hierarchical://%s/ledgers", - BookKeeperClusterUtils.zookeeperConnectString(docker)); - int numEntries = 100; - - try (BookKeeper bk = BookKeeper.newBuilder( - new ClientConfiguration().setMetadataServiceUri(zookeeper)).build()) { - log.info("Writing entries"); - long ledgerId = writeNEntries(bk, numEntries, 1); - - log.info("Dumping ledger metadata to file"); - String bookie = BookKeeperClusterUtils.getAnyBookie(); - String dumpFile = String.format("/tmp/ledger-%d-%d", ledgerId, System.nanoTime()); - DockerUtils.runCommand(docker, bookie, - bkScript, "shell", "ledgermetadata", - "--ledgerid", String.valueOf(ledgerId), - "--dumptofile", dumpFile); - - log.info("Delete the ledger metadata"); - bk.newDeleteLedgerOp().withLedgerId(ledgerId).execute().get(); - - // hopefully ledger gc doesn't kick in - log.info("Verify that we cannot open ledger"); - try { - validateNEntries(bk, ledgerId, numEntries); - Assert.fail("Shouldn't have been able to find anything"); - } catch (ExecutionException ee) { - Assert.assertEquals(ee.getCause().getClass(), - BKException.BKNoSuchLedgerExistsOnMetadataServerException.class); - } - - log.info("Restore the ledger metadata"); - DockerUtils.runCommand(docker, bookie, - bkScript, "shell", "ledgermetadata", - "--ledgerid", String.valueOf(ledgerId), - "--restorefromfile", dumpFile); - - log.info("Validate that we can read back, after regeneration"); - validateNEntries(bk, ledgerId, numEntries); - } - } - -} diff --git a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestCLI.java b/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestCLI.java deleted file mode 100644 index 66a78e9ca65..00000000000 --- a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestCLI.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.github.dockerjava.api.DockerClient; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tests.integration.utils.BookKeeperClusterUtils; -import org.apache.bookkeeper.tests.integration.utils.DockerUtils; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.arquillian.test.api.ArquillianResource; -import org.junit.Before; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; - -/** - * Test `bin/bkctl`. - */ -@Slf4j -@RunWith(Arquillian.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestCLI { - - @ArquillianResource - private DockerClient docker; - - private String currentVersion = System.getProperty("currentVersion"); - private String bkctl; - - @Before - public void setup() { - bkctl = "/opt/bookkeeper/" + currentVersion + "/bin/bkctl"; - } - - @Test - public void test000_Setup() throws Exception { - // First test to run, formats metadata and bookies - if (BookKeeperClusterUtils.metadataFormatIfNeeded(docker, currentVersion)) { - BookKeeperClusterUtils.formatAllBookies(docker, currentVersion); - } - assertTrue(BookKeeperClusterUtils.startAllBookiesWithVersion(docker, currentVersion)); - - } - - @Test - public void test999_Teardown() throws Exception { - assertTrue(BookKeeperClusterUtils.stopAllBookies(docker)); - } - - @Test - public void test001_SimpleTest() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - assertTrue(DockerUtils.runCommand(docker, bookie, - bkctl, - "ledger", - "simpletest", - "--ensemble-size", "3", - "--write-quorum-size", "3", - "--ack-quorum-size", "2", - "--num-entries", "100" - ).contains("100 entries written to ledger")); - } - - @Test - public void test002_ListROBookies() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - assertTrue(DockerUtils.runCommand(docker, bookie, - bkctl, - "bookies", - "list", - "-ro" - ).contains("No bookie exists!")); - } - - @Test - public void test003_ListRWBookies() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - assertTrue(DockerUtils.runCommand(docker, bookie, - bkctl, - "bookies", - "list", - "-rw" - ).contains("ReadWrite Bookies :")); - } - - @Test - public void test004_SearchReplaceBookieId() throws Exception { - String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker); - - String bookie = BookKeeperClusterUtils.getAnyBookie(); - int numEntries = 100; - try (BookKeeper bk = new BookKeeper(zookeeper)) { - long ledgerId; - BookieId toReplace; - BookieId replaceWith = BookieId.parse("192.0.2.1:3181"); - try (WriteHandle writelh = bk.newCreateLedgerOp() - .withDigestType(DigestType.CRC32C).withPassword(TestSmoke.PASSWD) - .withEnsembleSize(1).withWriteQuorumSize(1).withAckQuorumSize(1).execute().get()) { - ledgerId = writelh.getId(); - toReplace = writelh.getLedgerMetadata().getAllEnsembles().get(0L).get(0); - for (int i = 0; i < numEntries; i++) { - writelh.append(("entry-" + i).getBytes()); - } - } - - TestSmoke.readEntries(bk, ledgerId, numEntries); - - DockerUtils.runCommand(docker, bookie, - bkctl, - "bookieid", "searchreplace", - "--from", toReplace.toString(), - "--to", replaceWith.toString()); - - try { - TestSmoke.readEntries(bk, ledgerId, numEntries); - fail("Shouldn't be able to read, as bookie id is rubbish"); - } catch (BKException.BKBookieHandleNotAvailableException e) { - // expected - } - - DockerUtils.runCommand(docker, bookie, - bkctl, - "bookieid", "searchreplace", - "--from", replaceWith.toString(), - "--to", toReplace.toString()); - TestSmoke.readEntries(bk, ledgerId, numEntries); - } - } -} diff --git a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestDlogCLI.java b/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestDlogCLI.java deleted file mode 100644 index 34b88c1147b..00000000000 --- a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestDlogCLI.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.github.dockerjava.api.DockerClient; -import java.util.HashSet; -import java.util.Set; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.tests.integration.utils.BookKeeperClusterUtils; -import org.apache.bookkeeper.tests.integration.utils.DockerUtils; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.arquillian.test.api.ArquillianResource; -import org.junit.Before; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; - -/** - * Test `bin/dlog`. - */ -@Slf4j -@RunWith(Arquillian.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestDlogCLI { - - private static final String DLOG_STREAM_PREFIX = "stream-"; - private static final String STREAMS_REGEX = "0-99"; - - @ArquillianResource - private DockerClient docker; - - private String currentVersion = System.getProperty("currentVersion"); - private String dlogCLI; - private String dlogUri; - - @Before - public void setup() { - dlogCLI = "/opt/bookkeeper/" + currentVersion + "/bin/dlog"; - dlogUri = "distributedlog://" + BookKeeperClusterUtils.zookeeperConnectString(docker) + "/distributedlog"; - } - - @Test - public void test000_Setup() throws Exception { - // First test to run, formats metadata and bookies, then create a dlog namespace - if (BookKeeperClusterUtils.metadataFormatIfNeeded(docker, currentVersion)) { - BookKeeperClusterUtils.formatAllBookies(docker, currentVersion); - } - BookKeeperClusterUtils.createDlogNamespaceIfNeeded(docker, currentVersion, "/distributedlog"); - } - - @Test - public void test999_Teardown() throws Exception { - assertTrue(BookKeeperClusterUtils.stopAllBookies(docker)); - } - - @Test - public void test001_CreateStreams() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - assertTrue(DockerUtils.runCommand(docker, bookie, - dlogCLI, - "tool", - "create", - "--prefix", DLOG_STREAM_PREFIX, - "--expression", STREAMS_REGEX, - "--uri", dlogUri, - "-f" - ).isEmpty()); - } - - @Test - public void test002_ListStreams() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - String output = DockerUtils.runCommand(docker, bookie, - dlogCLI, - "tool", - "list", - "--uri", dlogUri, - "-f" - ); - String[] lines = output.split("\\r?\\n"); - Set streams = new HashSet<>(); - for (String string : lines) { - if (string.startsWith(DLOG_STREAM_PREFIX)) { - streams.add(string); - } - } - assertEquals(100, streams.size()); - } - - @Test - public void test003_ShowStream() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - String output = DockerUtils.runCommand(docker, bookie, true, - dlogCLI, - "tool", - "show", - "--uri", dlogUri, - "--stream", "stream-99", - "-f"); - assertTrue(output.contains("Log stream-99: has no records")); - } - - @Test - public void test004_DeleteStream() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - String output = DockerUtils.runCommand(docker, bookie, - dlogCLI, - "tool", - "delete", - "--uri", dlogUri, - "--stream", "stream-99", - "-f"); - assertTrue(output.isEmpty()); - } - - @Test - public void test005_CheckStreamDeleted() throws Exception { - String bookie = BookKeeperClusterUtils.getAnyBookie(); - String output = DockerUtils.runCommand(docker, bookie, true, - dlogCLI, - "tool", - "show", - "--uri", dlogUri, - "--stream", "stream-99", - "-f"); - assertTrue(output.contains("Log stream-99 does not exist or has been deleted")); - } - -} diff --git a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestSmoke.java b/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestSmoke.java deleted file mode 100644 index 1efa63d3f28..00000000000 --- a/tests/integration/smoke/src/test/java/org/apache/bookkeeper/tests/integration/TestSmoke.java +++ /dev/null @@ -1,324 +0,0 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF 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. -*/ -package org.apache.bookkeeper.tests.integration; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.bookkeeper.common.concurrent.FutureUtils.result; -import static org.junit.Assert.assertEquals; - -import com.github.dockerjava.api.DockerClient; -import com.google.common.base.Stopwatch; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.Enumeration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import lombok.Cleanup; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BKException.Code; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookKeeper.DigestType; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.tests.integration.utils.BookKeeperClusterUtils; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.arquillian.test.api.ArquillianResource; -import org.junit.Assert; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; - -/** - * Smoke tests for ledger apis. - */ -@Slf4j -@RunWith(Arquillian.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestSmoke { - static final byte[] PASSWD = "foobar".getBytes(); - - @ArquillianResource - DockerClient docker; - - private String currentVersion = System.getProperty("currentVersion"); - - @Test - public void test000_Setup() throws Exception { - // First test to run, formats metadata and bookies - if (BookKeeperClusterUtils.metadataFormatIfNeeded(docker, currentVersion)) { - BookKeeperClusterUtils.formatAllBookies(docker, currentVersion); - } - Assert.assertTrue(BookKeeperClusterUtils.startAllBookiesWithVersion(docker, currentVersion)); - } - - @Test - public void tear999_Teardown() { - Assert.assertTrue(BookKeeperClusterUtils.stopAllBookies(docker)); - } - - @Test - public void test001_ReadWrite() throws Exception { - String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker); - int numEntries = 100; - try (BookKeeper bk = new BookKeeper(zookeeper)) { - long ledgerId; - try (LedgerHandle writelh = bk.createLedger(BookKeeper.DigestType.CRC32C, PASSWD)) { - ledgerId = writelh.getId(); - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(("entry-" + i).getBytes()); - } - } - - readEntries(bk, ledgerId, numEntries); - } - } - - @Test - public void test002_ReadWriteAdv() throws Exception { - String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker); - int numEntries = 100; - try (BookKeeper bk = new BookKeeper(zookeeper)) { - long ledgerId; - try (LedgerHandle writelh = bk.createLedgerAdv(3, 3, 2, BookKeeper.DigestType.CRC32C, PASSWD)) { - ledgerId = writelh.getId(); - for (int i = 0; i < numEntries; i++) { - writelh.addEntry(i, ("entry-" + i).getBytes()); - } - } - - readEntries(bk, ledgerId, numEntries); - } - } - - static void readEntries(BookKeeper bk, - long ledgerId, - int numExpectedEntries) throws Exception { - try (LedgerHandle readlh = bk.openLedger(ledgerId, BookKeeper.DigestType.CRC32C, PASSWD)) { - long lac = readlh.getLastAddConfirmed(); - int i = 0; - Enumeration entries = readlh.readEntries(0, lac); - while (entries.hasMoreElements()) { - LedgerEntry e = entries.nextElement(); - String readBack = new String(e.getEntry()); - assertEquals(readBack, "entry-" + i++); - } - assertEquals(i, numExpectedEntries); - } - } - - @Test - public void test003_TailingReadsWithoutExplicitLac() throws Exception { - testTailingReads(100, 98, 0); - } - - @Test - public void test004_TailingReadsWithExplicitLac() throws Exception { - testTailingReads(100, 99, 100); - } - - private void testTailingReads(int numEntries, - long lastExpectedConfirmedEntryId, - int lacIntervalMs) - throws Exception { - String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker); - ClientConfiguration conf = new ClientConfiguration() - .setExplictLacInterval(lacIntervalMs) - .setMetadataServiceUri("zk://" + zookeeper + "/ledgers"); - @Cleanup BookKeeper bk = BookKeeper.forConfig(conf).build(); - @Cleanup LedgerHandle writeLh = bk.createLedger(DigestType.CRC32C, PASSWD); - @Cleanup("shutdown") ExecutorService writeExecutor = Executors.newSingleThreadExecutor( - new ThreadFactoryBuilder().setNameFormat("write-executor").build()); - - @Cleanup LedgerHandle readLh = bk.openLedgerNoRecovery(writeLh.getId(), DigestType.CRC32C, PASSWD); - @Cleanup("shutdown") ExecutorService readExecutor = Executors.newSingleThreadExecutor( - new ThreadFactoryBuilder().setNameFormat("read-executor").build()); - - CompletableFuture readFuture = new CompletableFuture<>(); - CompletableFuture writeFuture = new CompletableFuture<>(); - - // start the read thread - readExecutor.submit(() -> { - long nextEntryId = 0L; - try { - while (nextEntryId <= lastExpectedConfirmedEntryId) { - long lac = readLh.getLastAddConfirmed(); - while (lac >= nextEntryId) { - log.info("Attempt to read entries : [{} - {}]", - nextEntryId, lac); - Enumeration entries = readLh.readEntries(nextEntryId, lac); - while (entries.hasMoreElements()) { - LedgerEntry e = entries.nextElement(); - String readBack = new String(e.getEntry(), UTF_8); - log.info("Read entry {} : {}", e.getEntryId(), readBack); - assertEquals(readBack, "entry-" + (nextEntryId++)); - } - assertEquals(lac + 1, nextEntryId); - } - - if (nextEntryId > lastExpectedConfirmedEntryId) { - break; - } - - // refresh lac - readLh.readLastConfirmed(); - while (readLh.getLastAddConfirmed() < nextEntryId) { - log.info("Refresh lac {}, next entry id = {}", - readLh.getLastAddConfirmed(), nextEntryId); - TimeUnit.MILLISECONDS.sleep(100L); - - readLh.readLastConfirmed(); - if (readLh.getLastAddConfirmed() < nextEntryId) { - readLh.readExplicitLastConfirmed(); - } - } - } - FutureUtils.complete(readFuture, null); - log.info("Completed tailing read ledger {}", writeLh.getId()); - } catch (Exception e) { - log.error("Exceptions thrown during tailing read ledger {}", writeLh.getId(), e); - readFuture.completeExceptionally(e); - } - }); - - // start the write thread - writeEntries(numEntries, writeLh, writeExecutor, writeFuture); - - // both write and read should be successful - result(readFuture); - result(writeFuture); - - assertEquals(lastExpectedConfirmedEntryId, readLh.getLastAddConfirmed()); - assertEquals(numEntries - 1, writeLh.getLastAddConfirmed()); - assertEquals(numEntries - 1, writeLh.getLastAddPushed()); - } - - private static void writeEntries(int numEntries, - LedgerHandle writeLh, - ExecutorService writeExecutor, - CompletableFuture writeFuture) { - writeExecutor.submit(() -> { - try { - for (int i = 0; i < 100; i++) { - writeLh.addEntry(("entry-" + i).getBytes()); - } - log.info("Completed writing {} entries to ledger {}", numEntries, writeLh.getId()); - FutureUtils.complete(writeFuture, null); - } catch (Exception e) { - log.error("Exceptions thrown during writing {} entries to ledger {}", numEntries, writeLh.getId(), e); - writeFuture.completeExceptionally(e); - } - }); - } - - @Test - public void test005_LongTailingReadsWithoutExplicitLac() throws Exception { - testLongPollTailingReads(100, 98, 0); - } - - @Test - public void test006_LongTailingReadsWithExplicitLac() throws Exception { - testLongPollTailingReads(100, 99, 100); - } - - private void testLongPollTailingReads(int numEntries, - long lastExpectedConfirmedEntryId, - int lacIntervalMs) - throws Exception { - String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker); - ClientConfiguration conf = new ClientConfiguration() - .setExplictLacInterval(lacIntervalMs) - .setMetadataServiceUri("zk://" + zookeeper + "/ledgers"); - @Cleanup BookKeeper bk = BookKeeper.forConfig(conf).build(); - @Cleanup LedgerHandle writeLh = bk.createLedger(DigestType.CRC32C, PASSWD); - @Cleanup("shutdown") ExecutorService writeExecutor = Executors.newSingleThreadExecutor( - new ThreadFactoryBuilder().setNameFormat("write-executor").build()); - - @Cleanup LedgerHandle readLh = bk.openLedgerNoRecovery(writeLh.getId(), DigestType.CRC32C, PASSWD); - @Cleanup("shutdown") ScheduledExecutorService readExecutor = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder().setNameFormat("read-executor").build()); - - CompletableFuture readFuture = new CompletableFuture<>(); - CompletableFuture writeFuture = new CompletableFuture<>(); - - // start the read thread - AtomicLong nextEntryId = new AtomicLong(0L); - - Runnable readNextFunc = new Runnable() { - - @Override - public void run() { - if (nextEntryId.get() > lastExpectedConfirmedEntryId) { - FutureUtils.complete(readFuture, null); - return; - } - - Stopwatch readWatch = Stopwatch.createStarted(); - log.info("Attempt to read next entry {} - lac {}", nextEntryId.get(), readLh.getLastAddConfirmed()); - readLh.asyncReadLastConfirmedAndEntry(nextEntryId.get(), Long.MAX_VALUE / 2, false, - (rc, lastConfirmed, entry, ctx) -> { - log.info("Read return in {} ms : rc = {}, lac = {}, entry = {}", - readWatch.elapsed(TimeUnit.MILLISECONDS), rc, lastConfirmed, entry); - if (Code.OK == rc) { - if (null != entry) { - log.info("Successfully read entry {} : {}", - entry.getEntryId(), new String(entry.getEntry(), UTF_8)); - if (entry.getEntryId() != nextEntryId.get()) { - log.error("Attempt to read entry {} but received entry {}", - nextEntryId.get(), entry.getEntryId()); - readFuture.completeExceptionally( - BKException.create(Code.UnexpectedConditionException)); - return; - } else { - nextEntryId.incrementAndGet(); - } - } - readExecutor.submit(this); - } else if (Code.NoSuchLedgerExistsException == rc) { - // the ledger hasn't been created yet. - readExecutor.schedule(this, 200, TimeUnit.MILLISECONDS); - } else { - log.error("Failed to read entries : {}", BKException.getMessage(rc)); - readFuture.completeExceptionally(BKException.create(rc)); - } - }, null); - } - }; - - readNextFunc.run(); - - // start the write thread - writeEntries(numEntries, writeLh, writeExecutor, writeFuture); - - // both write and read should be successful - result(readFuture); - result(writeFuture); - - assertEquals(lastExpectedConfirmedEntryId + 1, nextEntryId.get()); - assertEquals(lastExpectedConfirmedEntryId, readLh.getLastAddConfirmed()); - assertEquals(numEntries - 1, writeLh.getLastAddConfirmed()); - assertEquals(numEntries - 1, writeLh.getLastAddPushed()); - } - -} diff --git a/tests/integration/standalone/src/test/java/org/apache/bookkeeper/tests/integration/standalone/StandaloneTest.java b/tests/integration/standalone/src/test/java/org/apache/bookkeeper/tests/integration/standalone/StandaloneTest.java deleted file mode 100644 index 29c30c369bf..00000000000 --- a/tests/integration/standalone/src/test/java/org/apache/bookkeeper/tests/integration/standalone/StandaloneTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tests.integration.standalone; - -import static org.junit.Assert.assertTrue; - -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.tests.containers.BKStandaloneContainer; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.testcontainers.containers.Container.ExecResult; - -/** - * A simple test to cover running current docker image in standalone mode. - */ -@Slf4j -public class StandaloneTest { - - @Rule - public final TestName testName = new TestName(); - - @ClassRule - public static BKStandaloneContainer bkContainer = new BKStandaloneContainer<>("integrationtest", 3); - - @Test - public void runSimpleTest() throws Exception { - ExecResult result = bkContainer.execCmd( - "/opt/bookkeeper/bin/bookkeeper", - "shell", - "simpletest", - "-ensemble", "3", - "-writeQuorum", "3", - "-ackQuorum", "2", - "-numEntries", "100" - ); - assertTrue( - result.getStdout().contains("100 entries written to ledger")); - } - - // - // `namespace` commands - // - - @Test - public void createNamespace() throws Exception { - String nsName = testName.getMethodName(); - ExecResult result = bkContainer.execCmd( - "/opt/bookkeeper/bin/bkctl", - "-u bk://localhost:4181", - "namespace", - "create", - nsName - ); - assertTrue( - result.getStdout(), - result.getStdout().contains("Successfully created namespace '" + nsName + "'")); - } - - // - // `tables` commands - // - - @Test - public void createTable() throws Exception { - createNamespace(); - String tableName = testName.getMethodName(); - ExecResult result = bkContainer.execCmd( - "/opt/bookkeeper/bin/bkctl", - "-u bk://localhost:4181", - "--namespace", - testName.getMethodName(), - "tables", - "create", - tableName - ); - assertTrue( - result.getStdout(), - result.getStdout().contains("Successfully created table '" + tableName + "'")); - } - -} diff --git a/tests/shaded/bookkeeper-server-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerShadedJarTest.java b/tests/shaded/bookkeeper-server-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerShadedJarTest.java deleted file mode 100644 index eba29f14a47..00000000000 --- a/tests/shaded/bookkeeper-server-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerShadedJarTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tests.shaded; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Test whether the bookkeeper-server-shaded jar is generated correctly. - */ -public class BookKeeperServerShadedJarTest { - - @Test(expected = ClassNotFoundException.class) - public void testProtobufIsShaded() throws Exception { - Class.forName("com.google.protobuf.Message"); - } - - @Test - public void testProtobufShadedPath() throws Exception { - Class.forName("org.apache.bookkeeper.shaded.com.google.protobuf.Message"); - } - - @Test(expected = ClassNotFoundException.class) - public void testGuavaIsShaded() throws Exception { - Class.forName("com.google.common.cache.Cache"); - } - - @Test - public void testGuavaShadedPath() throws Exception { - Class.forName("org.apache.bookkeeper.shaded.com.google.common.cache.Cache"); - assertTrue(true); - } - - @Test - public void testBookKeeperCommon() throws Exception { - Class.forName("org.apache.bookkeeper.common.util.OrderedExecutor"); - assertTrue(true); - } - - @Test - public void testBookKeeperProto() throws Exception { - Class.forName("org.apache.bookkeeper.proto.BookkeeperProtocol"); - assertTrue(true); - } - - @Test - public void testCirceChecksum() throws Exception { - Class.forName("com.scurrilous.circe.checksum.Crc32cIntChecksum"); - assertTrue(true); - } -} diff --git a/tests/shaded/bookkeeper-server-tests-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerTestsShadedJarTest.java b/tests/shaded/bookkeeper-server-tests-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerTestsShadedJarTest.java deleted file mode 100644 index 1f5eddd85fc..00000000000 --- a/tests/shaded/bookkeeper-server-tests-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/BookKeeperServerTestsShadedJarTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tests.shaded; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Test whether the bookkeeper-server-tests-shaded jar is generated correctly. - */ -public class BookKeeperServerTestsShadedJarTest { - - @Test - public void testTestBKConfiguration() throws Exception { - Class.forName("org.apache.bookkeeper.conf.TestBKConfiguration"); - assertTrue(true); - } - - /** - * TestPerChannelBookieClient imports protobuf classes. - */ - @Test - public void testTestPerChannelBookieClient() throws Exception { - Class.forName("org.apache.bookkeeper.proto.TestPerChannelBookieClient"); - assertTrue(true); - } - - /** - * BookieShellTest imports guava classes. - */ - @Test - public void testBookieShellTest() throws Exception { - Class.forName("org.apache.bookkeeper.bookie.BookieShellTest"); - assertTrue(true); - } - -} diff --git a/tests/shaded/distributedlog-core-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/DistributedLogCoreShadedJarTest.java b/tests/shaded/distributedlog-core-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/DistributedLogCoreShadedJarTest.java deleted file mode 100644 index 9dc6ee01932..00000000000 --- a/tests/shaded/distributedlog-core-shaded-test/src/test/java/org/apache/bookkeeper/tests/shaded/DistributedLogCoreShadedJarTest.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tests.shaded; - -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - - -import dlshade.org.apache.bookkeeper.common.util.ReflectionUtils; -import dlshade.org.apache.bookkeeper.conf.AbstractConfiguration; -import dlshade.org.apache.bookkeeper.conf.ServerConfiguration; -import dlshade.org.apache.bookkeeper.meta.AbstractZkLedgerManagerFactory; -import dlshade.org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory; -import dlshade.org.apache.bookkeeper.meta.LayoutManager; -import dlshade.org.apache.bookkeeper.meta.LedgerLayout; -import dlshade.org.apache.bookkeeper.meta.LedgerManagerFactory; -import java.io.IOException; -import lombok.Cleanup; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Test whether the distributedlog-core-shaded jar is generated correctly. - */ -@RunWith(MockitoJUnitRunner.class) -public class DistributedLogCoreShadedJarTest { - - @Test(expected = ClassNotFoundException.class) - public void testProtobufIsShaded() throws Exception { - Class.forName("com.google.protobuf.Message"); - } - - @Test - public void testProtobufShadedPath() throws Exception { - Class.forName("dlshade.com.google.protobuf.Message"); - } - - @Test(expected = ClassNotFoundException.class) - public void testGuavaIsShaded() throws Exception { - Class.forName("com.google.common.cache.Cache"); - } - - @Test - public void testGuavaShadedPath() throws Exception { - Class.forName("dlshade.com.google.common.cache.Cache"); - assertTrue(true); - } - - @Test(expected = ClassNotFoundException.class) - public void testZooKeeperIsShaded() throws Exception { - Class.forName("org.apache.zookeeper.ZooKeeper"); - } - - @Test - public void testZooKeeperShadedPath() throws Exception { - Class.forName("dlshade.org.apache.zookeeper.ZooKeeper"); - } - - @Test(expected = ClassNotFoundException.class) - public void testBookKeeperCommon() throws Exception { - Class.forName("org.apache.bookkeeper.common.util.OrderedExecutor"); - assertTrue(true); - } - - @Test - public void testBookKeeperCommonShade() throws Exception { - Class.forName("dlshade.org.apache.bookkeeper.common.util.OrderedExecutor"); - assertTrue(true); - } - - @Test(expected = ClassNotFoundException.class) - public void testBookKeeperProto() throws Exception { - Class.forName("org.apache.bookkeeper.proto.BookkeeperProtocol"); - } - - @Test - public void testBookKeeperProtoShade() throws Exception { - Class.forName("dlshade.org.apache.bookkeeper.proto.BookkeeperProtocol"); - assertTrue(true); - } - - @Test(expected = ClassNotFoundException.class) - public void testCirceChecksum() throws Exception { - Class.forName("com.scurrilous.circe.checksum.Crc32cIntChecksum"); - } - - @Test - public void testCirceChecksumShade() throws Exception { - Class.forName("dlshade.com.scurrilous.circe.checksum.Crc32cIntChecksum"); - assertTrue(true); - } - - @Test - public void testDistributedLogCommon() throws Exception { - Class.forName("dlshade.org.apache.distributedlog.common.concurrent.AsyncSemaphore"); - assertTrue(true); - } - - @Test - public void testDistributedLogProto() throws Exception { - Class.forName("dlshade.org.apache.distributedlog.DLSN"); - assertTrue(true); - } - - @Test - public void testDistributedLogCore() throws Exception { - Class.forName("dlshade.org.apache.distributedlog.api.AsyncLogReader"); - assertTrue(true); - } - - @Test - public void testShadeLedgerManagerFactoryWithoutConfiguredLedgerManagerClass() throws Exception { - testShadeLedgerManagerFactoryAllowed( - null, - true); - } - - - @Test - public void testShadeLedgerManagerFactoryWithConfiguredLedgerManagerClass() throws Exception { - testShadeLedgerManagerFactoryAllowed( - "org.apache.bookkeeper.meta.HirerchicalLedgerManagerFactory", - true); - } - - @Test - public void testShadeLedgerManagerFactoryDisallowedWithoutConfiguredLedgerManagerClass() throws Exception { - testShadeLedgerManagerFactoryAllowed( - null, - false); - } - - - @Test - public void testShadeLedgerManagerFactoryDisallowedWithConfiguredLedgerManagerClass() throws Exception { - testShadeLedgerManagerFactoryAllowed( - "org.apache.bookkeeper.meta.HirerchicalLedgerManagerFactory", - false); - } - - @SuppressWarnings("unchecked") - private void testShadeLedgerManagerFactoryAllowed(String factoryClassName, - boolean allowShaded) throws Exception { - ServerConfiguration conf = new ServerConfiguration(); - conf.setAllowShadedLedgerManagerFactoryClass(allowShaded); - conf.setLedgerManagerFactoryClassName(factoryClassName); - - LayoutManager manager = mock(LayoutManager.class); - LedgerLayout layout = new LedgerLayout( - "org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory", - HierarchicalLedgerManagerFactory.CUR_VERSION); - when(manager.readLedgerLayout()).thenReturn(layout); - - LedgerManagerFactory factory = mock(LedgerManagerFactory.class); - when(factory.initialize(any(AbstractConfiguration.class), same(manager), anyInt())) - .thenReturn(factory); - - @Cleanup - MockedStatic reflectionUtilsMockedStatic = mockStatic(ReflectionUtils.class); - reflectionUtilsMockedStatic.when(()-> ReflectionUtils.newInstance(any(Class.class))).thenReturn(factory); - - try { - LedgerManagerFactory result = AbstractZkLedgerManagerFactory.newLedgerManagerFactory( - conf, manager); - if (allowShaded) { - assertSame(factory, result); - verify(factory, times(1)) - .initialize(any(AbstractConfiguration.class), same(manager), anyInt()); - } else { - fail("Should fail to instantiate ledger manager factory if allowShaded is false"); - } - } catch (IOException ioe) { - if (allowShaded) { - fail("Should not fail to instantiate ledger manager factory is allowShaded is true"); - } else { - assertTrue(ioe.getCause() instanceof ClassNotFoundException); - } - } - } -} diff --git a/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/CliTest.java b/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/CliTest.java deleted file mode 100644 index 150f551f1f5..00000000000 --- a/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/CliTest.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.framework; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.tools.framework.TestCli.TestNestedFlags; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Testing the Cli framework using {@link TestCli}. - */ -public class CliTest { - - private ByteArrayOutputStream consoleBuffer; - private PrintStream console; - - @Before - public void setup() throws Exception { - this.consoleBuffer = new ByteArrayOutputStream(); - this.console = new PrintStream(consoleBuffer, true, UTF_8.name()); - } - - @Test - public void testEmptyArgs() { - assertEquals(-1, TestCli.doMain(console, new String[] {})); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - assertTrue(consoleBufferStr.contains("Usage:")); - assertTrue(consoleBufferStr.contains("Commands:")); - assertTrue(consoleBufferStr.contains("Flags:")); - } - - @Test - public void testHelpCommand() { - assertEquals(0, TestCli.doMain(console, new String[] { - "help" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - assertTrue(consoleBufferStr.contains("Usage:")); - assertTrue(consoleBufferStr.contains("Commands:")); - assertTrue(consoleBufferStr.contains("Flags:")); - } - - @Test - public void testHelpFlag() throws Exception { - assertEquals(0, TestCli.doMain(console, new String[] { - "help" - })); - String buffer1 = new String(consoleBuffer.toByteArray(), UTF_8); - - ByteArrayOutputStream anotherBuffer = new ByteArrayOutputStream(); - PrintStream anotherConsole = new PrintStream(anotherBuffer, true, UTF_8.name()); - - assertEquals(-1, TestCli.doMain(anotherConsole, new String[] { - "-h" - })); - String buffer2 = new String(anotherBuffer.toByteArray(), UTF_8); - - assertEquals(buffer1, buffer2); - } - - @Test - public void testPrintCommandUsage() throws Exception { - assertEquals(0, TestCli.doMain(console, new String[] { - "help", "dog" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - ByteArrayOutputStream expectedBufferStream = new ByteArrayOutputStream(); - PrintStream expectedConsole = new PrintStream(expectedBufferStream, true, UTF_8.name()); - expectedConsole.println("command dog"); - String expectedBuffer = new String(expectedBufferStream.toByteArray(), UTF_8); - - assertEquals(expectedBuffer, consoleBufferStr); - } - - @Test - public void testPrintHelpCommandUsage() throws Exception { - assertEquals(0, TestCli.doMain(console, new String[] { - "help", "help" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - assertTrue(consoleBufferStr.contains( - "Usage: bktest help [command] [options]" - )); - } - - @Test - public void testInvalidFlags() throws Exception { - assertEquals(-1, TestCli.doMain(console, new String[] { - "-s", "string", - "-i", "1234", - "-l" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - assertTrue(consoleBufferStr.contains("Error : Expected a value after parameter -l")); - // help message should be printed - assertTrue(consoleBufferStr.contains("Usage:")); - assertTrue(consoleBufferStr.contains("Commands:")); - assertTrue(consoleBufferStr.contains("Flags:")); - } - - @Test - public void testNestedCommandEmptySubCommand() { - assertEquals(-1, TestCli.doMain(console, new String[] { - "nested" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - // should print usage of 'nested' command - assertTrue(consoleBufferStr.contains("Usage: bktest nested")); - assertTrue(consoleBufferStr.contains("Commands:")); - assertTrue(consoleBufferStr.contains("cat")); - assertTrue(consoleBufferStr.contains("fish")); - assertTrue(consoleBufferStr.contains("Flags:")); - assertTrue(consoleBufferStr.contains("--nested-int-flag")); - } - - @Test - public void testNestedCommandHelpCommand() { - assertEquals(0, TestCli.doMain(console, new String[] { - "nested", "help" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - // should print usage of 'nested' command - assertTrue(consoleBufferStr.contains("Usage: bktest nested")); - assertTrue(consoleBufferStr.contains("Commands:")); - assertTrue(consoleBufferStr.contains("cat")); - assertTrue(consoleBufferStr.contains("fish")); - assertTrue(consoleBufferStr.contains("Flags:")); - assertTrue(consoleBufferStr.contains("--nested-int-flag")); - } - - @Test - public void testNestedCommandHelpFlag() throws Exception { - assertEquals(0, TestCli.doMain(console, new String[] { - "nested", "help" - })); - String buffer1 = new String(consoleBuffer.toByteArray(), UTF_8); - - ByteArrayOutputStream anotherBuffer = new ByteArrayOutputStream(); - PrintStream anotherConsole = new PrintStream(anotherBuffer, true, UTF_8.name()); - - assertEquals(-1, TestCli.doMain(anotherConsole, new String[] { - "nested", "-h" - })); - String buffer2 = new String(anotherBuffer.toByteArray(), UTF_8); - - assertEquals(buffer1, buffer2); - } - - @Test - public void testPrintSubCommandUsage() throws Exception { - assertEquals(0, TestCli.doMain(console, new String[] { - "nested", "help", "cat" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - ByteArrayOutputStream expectedBufferStream = new ByteArrayOutputStream(); - PrintStream expectedConsole = new PrintStream(expectedBufferStream, true, UTF_8.name()); - expectedConsole.println("command cat"); - String expectedBuffer = new String(expectedBufferStream.toByteArray(), UTF_8); - - assertEquals(expectedBuffer, consoleBufferStr); - } - - @Test - public void testPrintHelpSubCommandUsage() throws Exception { - assertEquals(0, TestCli.doMain(console, new String[] { - "nested", "help", "help" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - assertTrue(consoleBufferStr.contains( - "Usage: bktest nested help [command] [options]" - )); - } - - @Test - public void testSubCommandInvalidFlags() throws Exception { - assertEquals(-1, TestCli.doMain(console, new String[] { - "nested", - "-s", "string", - "-i", "1234", - "-l" - })); - - String consoleBufferStr = new String(consoleBuffer.toByteArray(), UTF_8); - - assertTrue(consoleBufferStr.contains("Error : Expected a value after parameter -l")); - // help message should be printed - assertTrue(consoleBufferStr.contains("Usage: bktest nested")); - assertTrue(consoleBufferStr.contains("Commands:")); - assertTrue(consoleBufferStr.contains("cat")); - assertTrue(consoleBufferStr.contains("fish")); - assertTrue(consoleBufferStr.contains("Flags:")); - assertTrue(consoleBufferStr.contains("--nested-int-flag")); - } - - @Test - public void testSubCommandFlags() throws Exception { - CompletableFuture flagsFuture = FutureUtils.createFuture(); - assertEquals(0, TestCli.doMain(console, new String[] { - "nested", - "-s", "string", - "-i", "1234", - "-l", "str1,str2,str3", - "additional-args" - }, (flags) -> flagsFuture.complete(flags))); - - dumpConsole(); - - TestNestedFlags flags = FutureUtils.result(flagsFuture); - assertEquals("string", flags.stringFlag); - assertEquals(1234, flags.intFlag); - Assert.assertEquals( - Lists.newArrayList("str1", "str2", "str3"), - flags.listFlag - ); - assertEquals(1, flags.arguments.size()); - Assert.assertEquals(Lists.newArrayList("additional-args"), flags.arguments); - } - - // - // Util functions - // - - private void dumpConsole() { - String buffer = new String( - consoleBuffer.toByteArray(), UTF_8); - - System.out.println(buffer); - } - -} diff --git a/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/TestCli.java b/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/TestCli.java deleted file mode 100644 index 3f5f678e05b..00000000000 --- a/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/TestCli.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.framework; - -import com.beust.jcommander.Parameter; -import com.google.common.collect.Lists; -import java.io.PrintStream; -import java.util.List; -import java.util.function.Function; -import org.apache.bookkeeper.tools.framework.commands.TestCommand; - -/** - * A CLI used for testing. - */ -public class TestCli { - - private static final String NAME = "bktest"; - - private static final String DESC = "bookkeeper test"; - - static class TestFlags extends CliFlags { - - @Parameter( - names = { - "-s", "--string-flag" - }, - description = "string flag") - public String stringFlag = null; - - @Parameter( - names = { - "-i", "--int-flag" - }, - description = "int flag") - public int intFlag = 0; - - @Parameter( - names = { - "-l", "--list-flags" - }, - description = "list flag") - public List listFlag = Lists.newArrayList(); - - } - - static class TestNestedFlags extends CliFlags { - - @Parameter( - names = { - "-s", "--nested-string-flag" - }, - description = "string flag") - public String stringFlag = null; - - @Parameter( - names = { - "-i", "--nested-int-flag" - }, - description = "int flag") - public int intFlag = 0; - - @Parameter( - names = { - "-l", "--nested-list-flags" - }, - description = "list flag") - public List listFlag = Lists.newArrayList(); - - } - - public static void main(String[] args) { - Runtime.getRuntime().exit( - doMain(System.out, args)); - } - - static int doMain(PrintStream console, String[] args) { - return doMain(console, args, null); - } - - static int doMain(PrintStream console, - String[] args, - Function func) { - String nestedCommandName = "nested"; - String nestedCommandDesc = "bookkeeper test-nested"; - CliSpec nestedSpec = CliSpec.newBuilder() - .withName(nestedCommandName) - .withParent(NAME) - .withDescription(nestedCommandDesc) - .withFlags(new TestNestedFlags()) - .withConsole(console) - .addCommand(new TestCommand("fish", console)) - .addCommand(new TestCommand("cat", console)) - .withRunFunc(func) - .build(); - CliCommand nestedCommand = - new CliCommand<>(nestedSpec); - - CliSpec spec = CliSpec.newBuilder() - .withName(NAME) - .withDescription(DESC) - .withFlags(new TestFlags()) - .withConsole(console) - .addCommand(new TestCommand("monkey", console)) - .addCommand(new TestCommand("dog", console)) - .addCommand(nestedCommand) - .build(); - - return Cli.runCli(spec, args); - } - - - -} diff --git a/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/commands/TestCommand.java b/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/commands/TestCommand.java deleted file mode 100644 index 19f10e2cfdf..00000000000 --- a/tools/framework/src/test/java/org/apache/bookkeeper/tools/framework/commands/TestCommand.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.framework.commands; - -import java.io.PrintStream; -import org.apache.bookkeeper.tools.framework.CliFlags; -import org.apache.bookkeeper.tools.framework.Command; - -/** - * Test Command. - */ -public class TestCommand implements Command { - - private final String label; - private final PrintStream console; - - public TestCommand(String label, - PrintStream console) { - this.label = label; - this.console = console; - } - - @Override - public String name() { - return label; - } - - @Override - public String description() { - return "Command " + label; - } - - @Override - public Boolean apply(CliFlags globalFlags, String[] args) { - return true; - } - - @Override - public void usage() { - console.println("command " + label); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/AutoRecoveryCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/AutoRecoveryCommandTest.java deleted file mode 100644 index dd0d3d9a3e7..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/AutoRecoveryCommandTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.autorecovery; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.replication.ReplicationException; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.zookeeper.KeeperException; -import org.junit.Assert; -import org.junit.Test; - - -/** - * Unit test for {@link ToggleCommand}. - */ -@SuppressWarnings("unchecked") -public class AutoRecoveryCommandTest extends BookieCommandTestBase { - - private LedgerManagerFactory ledgerManagerFactory; - private LedgerUnderreplicationManager ledgerUnderreplicationManager; - - public AutoRecoveryCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - ledgerManagerFactory = mock(LedgerManagerFactory.class); - mockMetadataDriversWithLedgerManagerFactory(ledgerManagerFactory); - - ledgerUnderreplicationManager = mock(LedgerUnderreplicationManager.class); - when(ledgerManagerFactory.newLedgerUnderreplicationManager()).thenReturn(ledgerUnderreplicationManager); - } - - @Test - public void testWithEnable() - throws InterruptedException, ReplicationException.CompatibilityException, KeeperException, - ReplicationException.UnavailableException { - testCommand("-e"); - verify(ledgerManagerFactory, times(1)).newLedgerUnderreplicationManager(); - verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled(); - } - - @Test - public void testWithEnableLongArgs() throws ReplicationException.UnavailableException { - when(ledgerUnderreplicationManager.isLedgerReplicationEnabled()).thenReturn(false); - testCommand("--enable"); - verify(ledgerUnderreplicationManager, times(1)).enableLedgerReplication(); - } - - @Test - public void testWithLook() - throws InterruptedException, ReplicationException.CompatibilityException, KeeperException, - ReplicationException.UnavailableException { - testCommand("s"); - verify(ledgerManagerFactory, times(1)).newLedgerUnderreplicationManager(); - verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled(); - } - - @Test - public void testWithNoArgs() - throws InterruptedException, ReplicationException.CompatibilityException, KeeperException, - ReplicationException.UnavailableException { - testCommand(""); - verify(ledgerManagerFactory, times(1)).newLedgerUnderreplicationManager(); - verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled(); - } - - @Test - public void testWithNoArgsDisable() throws ReplicationException.UnavailableException { - when(ledgerUnderreplicationManager.isLedgerReplicationEnabled()).thenReturn(true); - testCommand(""); - verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled(); - verify(ledgerUnderreplicationManager, times(1)).disableLedgerReplication(); - } - - private void testCommand(String... args) { - ToggleCommand cmd = new ToggleCommand(); - Assert.assertTrue(cmd.apply(bkFlags, args)); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/ListUnderReplicatedCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/ListUnderReplicatedCommandTest.java deleted file mode 100644 index b0453980bca..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/ListUnderReplicatedCommandTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.autorecovery; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Vector; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.UnderreplicatedLedger; -import org.apache.bookkeeper.replication.ReplicationException; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.zookeeper.KeeperException; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link ListUnderReplicatedCommand}. - */ -public class ListUnderReplicatedCommandTest extends BookieCommandTestBase { - - private UnderreplicatedLedger ledger; - private LedgerManagerFactory factory; - private LedgerUnderreplicationManager underreplicationManager; - - public ListUnderReplicatedCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - factory = mock(LedgerManagerFactory.class); - mockMetadataDriversWithLedgerManagerFactory(factory); - - underreplicationManager = mock(LedgerUnderreplicationManager.class); - when(factory.newLedgerUnderreplicationManager()).thenReturn(underreplicationManager); - - ledger = mock(UnderreplicatedLedger.class); - when(ledger.getLedgerId()).thenReturn(1L); - when(ledger.getCtime()).thenReturn(1L); - - Vector ledgers = new Vector<>(); - ledgers.add(ledger); - - when(underreplicationManager.listLedgersToRereplicate(any())).thenReturn(ledgers.iterator()); - - } - - @Test - public void testWithoutArgs() - throws InterruptedException, ReplicationException { - testCommand(""); - verify(factory, times(1)).newLedgerUnderreplicationManager(); - verify(underreplicationManager, times(1)).listLedgersToRereplicate(any()); - verify(ledger, times(1)).getLedgerId(); - verify(ledger, times(1)).getCtime(); - } - - @Test - public void testMissingReplica() - throws InterruptedException, ReplicationException { - testCommand("-mr", ""); - verify(factory, times(1)).newLedgerUnderreplicationManager(); - verify(underreplicationManager, times(1)).listLedgersToRereplicate(any()); - verify(ledger, times(1)).getLedgerId(); - verify(ledger, times(1)).getCtime(); - } - - @Test - public void testExcludingMissingReplica() - throws InterruptedException, ReplicationException { - testCommand("-emr", ""); - verify(factory, times(1)).newLedgerUnderreplicationManager(); - verify(underreplicationManager, times(1)).listLedgersToRereplicate(any()); - verify(ledger, times(1)).getLedgerId(); - verify(ledger, times(1)).getCtime(); - } - - @Test - public void testPrintMissingReplica() - throws InterruptedException, ReplicationException { - - ArrayList list = new ArrayList<>(); - list.add("replica"); - - when(ledger.getReplicaList()).thenReturn(list); - testCommand("-pmr"); - verify(factory, times(1)).newLedgerUnderreplicationManager(); - verify(underreplicationManager, times(1)).listLedgersToRereplicate(any()); - verify(ledger, times(1)).getLedgerId(); - verify(ledger, times(1)).getCtime(); - verify(ledger, times(1)).getReplicaList(); - } - - @Test - public void testPrintReplicationWorkerId() throws ReplicationException.UnavailableException, InterruptedException, - ReplicationException.CompatibilityException, KeeperException { - when(underreplicationManager.getReplicationWorkerIdRereplicatingLedger(1L)).thenReturn("test"); - - testCommand("-prw"); - verify(factory, times(1)).newLedgerUnderreplicationManager(); - verify(underreplicationManager, times(1)).listLedgersToRereplicate(any()); - verify(ledger, times(1)).getLedgerId(); - verify(ledger, times(1)).getCtime(); - verify(underreplicationManager, times(1)).getReplicationWorkerIdRereplicatingLedger(1L); - } - - @Test - public void testOnlyDisplayLedgerCount() throws InterruptedException, KeeperException, - ReplicationException.CompatibilityException, ReplicationException.UnavailableException { - testCommand("-c"); - - verify(factory, times(1)).newLedgerUnderreplicationManager(); - verify(underreplicationManager, times(1)).listLedgersToRereplicate(any()); - verify(underreplicationManager, times(0)) - .getReplicationWorkerIdRereplicatingLedger(anyLong()); - verify(ledger, times(0)).getLedgerId(); - verify(ledger, times(0)).getCtime(); - verify(ledger, times(0)).getReplicaList(); - } - - @Test - public void testCommand1() { - ListUnderReplicatedCommand cmd = new ListUnderReplicatedCommand(); - cmd.apply(bkFlags, new String[] { "" }); - } - - private void testCommand(String... args) { - ListUnderReplicatedCommand cmd = new ListUnderReplicatedCommand(); - Assert.assertTrue(cmd.apply(bkFlags, args)); - } - -} - diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/LostBookieRecoveryDelayCommandTets.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/LostBookieRecoveryDelayCommandTets.java deleted file mode 100644 index 52fd4fd2529..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/LostBookieRecoveryDelayCommandTets.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.autorecovery; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.function.Consumer; -import lombok.SneakyThrows; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link LostBookieRecoveryDelayCommand}. - */ -public class LostBookieRecoveryDelayCommandTets extends BookieCommandTestBase { - - public LostBookieRecoveryDelayCommandTets() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockClientConfigurationConstruction(); - mockBookKeeperAdminConstruction( - new Consumer() { - @Override - @SneakyThrows - public void accept(BookKeeperAdmin bookKeeperAdmin) { - when(bookKeeperAdmin.getLostBookieRecoveryDelay()).thenReturn(1); - doNothing().when(bookKeeperAdmin).setLostBookieRecoveryDelay(anyInt()); - } - } - ); - - } - - @Test - public void testWithoutArgs() { - LostBookieRecoveryDelayCommand cmd = new LostBookieRecoveryDelayCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[]{""})); - } - - @Test - public void testWithSet() throws Exception { - testCommand("-s", "1"); - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).setLostBookieRecoveryDelay(1); - } - - @Test - public void testWithGet() throws Exception { - testCommand("-g"); - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).getLostBookieRecoveryDelay(); - } - - private void testCommand(String... args) { - LostBookieRecoveryDelayCommand cmd = new LostBookieRecoveryDelayCommand(); - Assert.assertTrue(cmd.apply(bkFlags, args)); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/QueryAutoRecoveryStatusCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/QueryAutoRecoveryStatusCommandTest.java deleted file mode 100644 index e08adc0cffd..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/QueryAutoRecoveryStatusCommandTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.autorecovery; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import java.lang.reflect.Constructor; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerMetadataBuilder; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; -import org.apache.bookkeeper.meta.UnderreplicatedLedger; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieAddressResolver; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.tools.cli.helpers.CommandHelpers; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.Timeout; - -/** - * Unit test for {@link QueryAutoRecoveryStatusCommand}. - */ -public class QueryAutoRecoveryStatusCommandTest extends BookieCommandTestBase { - - @Rule - public final Timeout globalTimeout = Timeout.seconds(30); - - public QueryAutoRecoveryStatusCommandTest() { - super(3, 0); - } - LedgerUnderreplicationManager underreplicationManager; - - @Override - public void setup() throws Exception { - super.setup(); - BookieId bookieId = BookieId.parse(UUID.randomUUID().toString()); - LedgerManagerFactory ledgerManagerFactory = mock(LedgerManagerFactory.class); - - mockServerConfigurationConstruction(null); - mockMetadataDriversWithLedgerManagerFactory(ledgerManagerFactory); - - LedgerManager ledgerManager = mock(LedgerManager.class); - underreplicationManager = mock(LedgerUnderreplicationManager.class); - - when(ledgerManagerFactory.newLedgerManager()).thenReturn(ledgerManager); - when(ledgerManagerFactory.newLedgerUnderreplicationManager()).thenReturn(underreplicationManager); - - List ensemble = Lists.newArrayList(new BookieSocketAddress("192.0.2.1", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.2", 1234).toBookieId(), - new BookieSocketAddress("192.0.2.3", 1234).toBookieId()); - LedgerMetadata metadata = LedgerMetadataBuilder.create() - .withId(11112233) - .withClosedState() - .withLength(100000999) - .withLastEntryId(2000011) - .withEnsembleSize(3).withWriteQuorumSize(2).withAckQuorumSize(2) - .withPassword("passwd".getBytes()) - .withDigestType(BookKeeper.DigestType.CRC32.toApiDigestType()) - .newEnsembleEntry(0L, ensemble).build(); - CompletableFuture> promise = new CompletableFuture<>(); - Versioned vmeta = new Versioned(metadata, new LongVersion(1000)); - promise.complete(vmeta); - - when(ledgerManager.readLedgerMetadata(1)).thenReturn(promise); - when(ledgerManager.readLedgerMetadata(33232)).thenReturn(promise); - - Constructor constructor = UnderreplicatedLedger.class. - getDeclaredConstructor(long.class); - constructor.setAccessible(true); - final Queue queue = new LinkedList(); - queue.add("1111"); - Iterator iter = new Iterator() { - @Override - public boolean hasNext() { - if (queue.size() > 0) { - queue.remove(); - try { - curBatch.add(constructor.newInstance(1)); - curBatch.add(constructor.newInstance(33232)); - } catch (Exception e) { - } - } - - if (curBatch.size() > 0) { - return true; - } - return false; - } - - @Override - public UnderreplicatedLedger next() { - return curBatch.remove(); - } - - final Queue curBatch = new LinkedList(); - }; - - when(underreplicationManager.listLedgersToRereplicate(any())).thenReturn(iter); - - mockStatic(CommandHelpers.class, CALLS_REAL_METHODS).when(() -> CommandHelpers - .getBookieSocketAddrStringRepresentation( - eq(bookieId), any(BookieAddressResolver.class))).thenReturn(""); - } - - @Test() - public void testQueryRecoverStatusCommand() { - try { - when(underreplicationManager.getReplicationWorkerIdRereplicatingLedger(1)).thenReturn("192.168.0.103"); - when(underreplicationManager.getReplicationWorkerIdRereplicatingLedger(33232)).thenReturn("192.168.0.103"); - } catch (Exception e) { - } - QueryAutoRecoveryStatusCommand cmd = new QueryAutoRecoveryStatusCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - } - - @Test() - public void testQueryRecoverStatusCommandWithDetail() { - try { - when(underreplicationManager.getReplicationWorkerIdRereplicatingLedger(1)).thenReturn("192.168.0.103"); - when(underreplicationManager.getReplicationWorkerIdRereplicatingLedger(33232)).thenReturn("192.168.0.103"); - } catch (Exception e) { - } - QueryAutoRecoveryStatusCommand cmd = new QueryAutoRecoveryStatusCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-v" })); - } - - @Test() - public void testNoLedgerIsBeingRecovered() { - QueryAutoRecoveryStatusCommand cmd = new QueryAutoRecoveryStatusCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-v" })); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/TriggerAuditCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/TriggerAuditCommandTest.java deleted file mode 100644 index 189eb63940f..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/TriggerAuditCommandTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.autorecovery; - -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.function.Consumer; -import lombok.SneakyThrows; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link TriggerAuditCommand}. - */ -public class TriggerAuditCommandTest extends BookieCommandTestBase { - - - public TriggerAuditCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - - mockClientConfigurationConstruction(); - - - mockBookKeeperAdminConstruction(new Consumer(){ - @Override - @SneakyThrows - public void accept(BookKeeperAdmin bookKeeperAdmin) { - doNothing().when(bookKeeperAdmin).triggerAudit(); - } - }); - } - - @Test - public void testCommand() throws Exception { - TriggerAuditCommand cmd = new TriggerAuditCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).triggerAudit(); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/WhoIsAuditorCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/WhoIsAuditorCommandTest.java deleted file mode 100644 index 14a1c61549c..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/WhoIsAuditorCommandTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.autorecovery; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.UUID; -import lombok.Cleanup; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieAddressResolver; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.tools.cli.helpers.CommandHelpers; -import org.apache.bookkeeper.zookeeper.ZooKeeperClient; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link WhoIsAuditorCommand}. - */ -public class WhoIsAuditorCommandTest extends BookieCommandTestBase { - - public WhoIsAuditorCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockClientConfigurationConstruction(); - - ZooKeeperClient zk = mock(ZooKeeperClient.class); - ZooKeeperClient.Builder builder = mock(ZooKeeperClient.Builder.class); - - mockStatic(ZooKeeperClient.class).when(() -> ZooKeeperClient.newBuilder()).thenReturn(builder); - when(builder.connectString(anyString())).thenReturn(builder); - when(builder.sessionTimeoutMs(anyInt())).thenReturn(builder); - when(builder.build()).thenReturn(zk); - - BookieId bookieId = BookieId.parse(UUID.randomUUID().toString()); - - mockStatic(CommandHelpers.class, CALLS_REAL_METHODS).when(() -> CommandHelpers - .getBookieSocketAddrStringRepresentation( - eq(bookieId), any(BookieAddressResolver.class))).thenReturn(""); - } - - @Test - public void testCommand() throws Exception { - @Cleanup - BookKeeperAdmin bka = mock(BookKeeperAdmin.class); - when(bka.getCurrentAuditor()).thenReturn(BookieId.parse("127.0.0.1:3181")); - WhoIsAuditorCommand cmd = new WhoIsAuditorCommand(bka); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToDBStorageCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToDBStorageCommandTest.java deleted file mode 100644 index f6f9fdfad61..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToDBStorageCommandTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.util.concurrent.UncheckedExecutionException; -import java.util.Iterator; -import java.util.Vector; -import java.util.stream.LongStream; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerCache; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link ConvertToDBStorageCommand}. - */ -public class ConvertToDBStorageCommandTest extends BookieCommandTestBase { - - private LedgerCache.LedgerIndexMetadata metadata; - private LedgerCache.PageEntriesIterable entries; - - public ConvertToDBStorageCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - - metadata = mock(LedgerCache.LedgerIndexMetadata.class); - entries = mock(LedgerCache.PageEntriesIterable.class); - - mockConstruction(InterleavedLedgerStorage.class, (interleavedLedgerStorage, context) -> { - doNothing().when(interleavedLedgerStorage).shutdown(); - when(interleavedLedgerStorage.getActiveLedgersInRange(anyLong(), anyLong())).thenReturn( - ConvertToDBStorageCommandTest.this::getLedgerId); - when(interleavedLedgerStorage.readLedgerIndexMetadata(anyLong())).thenReturn(metadata); - when(interleavedLedgerStorage.getIndexEntries(anyLong())).thenReturn(entries); - }); - mockConstruction(DbLedgerStorage.class, (dbStorage, context) -> { - doNothing().when(dbStorage).shutdown(); - when(dbStorage.addLedgerToIndex(anyLong(), anyBoolean(), eq(new byte[0]), - any(LedgerCache.PageEntriesIterable.class))).thenReturn(1L); - }); - mockStatic(BookieImpl.class); - getMockedStatic(BookieImpl.class).when(() -> BookieImpl - .mountLedgerStorageOffline(any(ServerConfiguration.class), any(InterleavedLedgerStorage.class))) - .thenReturn(mock(InterleavedLedgerStorage.class)); - getMockedStatic(BookieImpl.class).when(() -> BookieImpl - .mountLedgerStorageOffline(any(ServerConfiguration.class), any(DbLedgerStorage.class))) - .thenAnswer((invocation) -> - getMockedConstruction(InterleavedLedgerStorage.class).constructed().get(0)); - } - - private Iterator getLedgerId() { - Vector longs = new Vector<>(); - LongStream.range(0L, 10L).forEach(longs::add); - return longs.iterator(); - } - - @Test - public void testCTDB() { - ConvertToDBStorageCommand cmd = new ConvertToDBStorageCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - - try { - InterleavedLedgerStorage interleavedLedgerStorage = getMockedConstruction(InterleavedLedgerStorage.class) - .constructed().get(0); - - DbLedgerStorage dbStorage = getMockedConstruction(DbLedgerStorage.class).constructed().get(0); - verify(interleavedLedgerStorage, times(10)).readLedgerIndexMetadata(anyLong()); - verify(interleavedLedgerStorage, times(10)).getIndexEntries(anyLong()); - verify(dbStorage, times(10)) - .addLedgerToIndex(anyLong(), anyBoolean(), any(), any(LedgerCache.PageEntriesIterable.class)); - verify(interleavedLedgerStorage, times(10)).deleteLedger(anyLong()); - - verify(dbStorage, times(1)).shutdown(); - verify(interleavedLedgerStorage, times(1)).shutdown(); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToInterleavedStorageCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToInterleavedStorageCommandTest.java deleted file mode 100644 index 8c29b0caac5..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ConvertToInterleavedStorageCommandTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.util.concurrent.UncheckedExecutionException; -import io.netty.buffer.PooledByteBufAllocator; -import java.io.File; -import java.io.IOException; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Vector; -import java.util.stream.LongStream; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerCache; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.util.DiskChecker; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link ConvertToInterleavedStorageCommand}. - */ -public class ConvertToInterleavedStorageCommandTest extends BookieCommandTestBase { - - private LedgerCache interleavedLedgerCache; - - - // create multi ledger dirs and multi index dirs - public ConvertToInterleavedStorageCommandTest() { - super(3, 3); - } - - @Override - public void setup() throws Exception { - super.setup(); - - createTmpFile(); - mockServerConfigurationConstruction(); - - mockConstruction(DiskChecker.class); - - mockConstruction(LedgerDirsManager.class, (ledgersDirManager, context) -> { - when(ledgersDirManager.getAllLedgerDirs()).thenReturn(getFileList()); - }); - - - mockConstruction(DbLedgerStorage.class, (dbStorage, context) -> { - when(dbStorage.getActiveLedgersInRange(anyLong(), anyLong())) - .thenReturn(ConvertToInterleavedStorageCommandTest.this::getLedgerId); - }); - - interleavedLedgerCache = mock(LedgerCache.class); - doNothing().when(interleavedLedgerCache).flushLedger(anyBoolean()); - - mockConstruction(InterleavedLedgerStorage.class, - (interleavedLedgerStorage, context) -> { - doNothing().when(interleavedLedgerStorage).flush(); - doNothing().when(interleavedLedgerStorage).shutdown(); - when(interleavedLedgerStorage.getLedgerCache()).thenReturn(interleavedLedgerCache); - }); - } - - - private Iterator getLedgerId() { - Vector longs = new Vector<>(); - LongStream.range(0L, 10L).forEach(longs::add); - return longs.iterator(); - } - - private List getFileList() { - List files = new LinkedList<>(); - files.add(testDir.getRoot()); - return files; - } - - private void createTmpFile() { - try { - testDir.newFile("ledgers"); - testDir.newFile("locations"); - } catch (IOException e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - } - - @Test - public void testConvertToInterleavedStorageCommand() { - ConvertToInterleavedStorageCommand cmd = new ConvertToInterleavedStorageCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - - try { - final DbLedgerStorage dbStorage = getMockedConstruction(DbLedgerStorage.class).constructed().get(0); - final InterleavedLedgerStorage interleavedLedgerStorage = - getMockedConstruction(InterleavedLedgerStorage.class).constructed().get(0); - verify(dbStorage, times(1)).initialize( - any(ServerConfiguration.class), eq(null), any(LedgerDirsManager.class), - any(LedgerDirsManager.class), eq(NullStatsLogger.INSTANCE), eq(PooledByteBufAllocator.DEFAULT)); - - verify(interleavedLedgerStorage, times(1)) - .initialize(any(ServerConfiguration.class), eq(null), any(LedgerDirsManager.class), - any(LedgerDirsManager.class), eq(NullStatsLogger.INSTANCE), eq(PooledByteBufAllocator.DEFAULT)); - verify(dbStorage, times(1)).getActiveLedgersInRange(anyLong(), anyLong()); - verify(dbStorage, times(10)).readMasterKey(anyLong()); - verify(interleavedLedgerStorage, times(10)).setMasterKey(anyLong(), any()); - verify(dbStorage, times(10)).getLastEntryInLedger(anyLong()); - verify(dbStorage, times(10)).getLocation(anyLong(), anyLong()); - verify(dbStorage, times(1)).shutdown(); - verify(interleavedLedgerCache, times(1)).flushLedger(true); - verify(interleavedLedgerStorage, times(1)).flush(); - verify(interleavedLedgerStorage, times(1)).shutdown(); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FlipBookieIdCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FlipBookieIdCommandTest.java deleted file mode 100644 index 6b44de7fe40..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FlipBookieIdCommandTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.internal.verification.VerificationModeFactory.times; - -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.UpdateLedgerOp; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link FlipBookieIdCommand}. - */ -public class FlipBookieIdCommandTest extends BookieCommandTestBase { - - private static final BookieId bookieSocketAddress = BookieId.parse("localhost:9000"); - - public FlipBookieIdCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockClientConfigurationConstruction(); - mockServerConfigurationConstruction(); - mockConstruction(BookKeeper.class); - mockBookKeeperAdminConstruction(); - mockConstruction(UpdateLedgerOp.class); - mockStatic(BookieImpl.class).when(() -> BookieImpl.getBookieId(any(ServerConfiguration.class))) - .thenReturn(bookieSocketAddress); - } - - @Test - public void testCommand() throws Exception { - FlipBookieIdCommand cmd = new FlipBookieIdCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - verify(getMockedConstruction(ClientConfiguration.class).constructed().get(0), times(1)) - .addConfiguration(any(ServerConfiguration.class)); - verify(getMockedConstruction(ServerConfiguration.class).constructed().get(1), times(1)) - .setUseHostNameAsBookieID(anyBoolean()); - verify(getMockedConstruction(UpdateLedgerOp.class).constructed().get(0), times(1)) - .updateBookieIdInLedgers(eq(bookieSocketAddress), eq(bookieSocketAddress), - anyInt(), anyInt(), anyInt(), any()); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FormatCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FormatCommandTest.java deleted file mode 100644 index 9cd1a9408d0..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/FormatCommandTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Test; -import org.mockito.MockedStatic; - -/** - * Unit test {@link FormatCommand}. - */ -public class FormatCommandTest extends BookieCommandTestBase { - - public FormatCommandTest() { - super(3, 0); - } - - @SuppressWarnings("unchecked") - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - - RegistrationManager rm = mock(RegistrationManager.class); - mockMetadataDriversWithRegistrationManager(rm); - - mockConstruction(Versioned.class, (cookie, context) -> { - assertEquals(context.arguments().get(1), new LongVersion(1L)); - when(cookie.getValue()).thenReturn(mock(Cookie.class)); - }); - - - final MockedStatic cookieMockedStatic = mockStatic(Cookie.class); - cookieMockedStatic.when(() -> Cookie.readFromRegistrationManager(eq(rm), any(ServerConfiguration.class))) - .thenAnswer(invocation -> new Versioned<>(mock(Cookie.class), new LongVersion(1L))); - } - - /** - * Test different type of command flags. - */ - @Test - public void testNonInteraction() { - testCommand("-n"); - } - - @Test - public void testNonInteractionLongArgs() { - testCommand("--noninteractive"); - } - - @Test - public void testForce() { - testCommand("-f"); - } - - @Test - public void testForceLongArgs() { - testCommand("--force"); - } - - @Test - public void testDeleteCookie() { - testCommand("-d"); - } - - @Test - public void testDeleteCookieLongArgs() { - testCommand("--deletecookie"); - } - - @Test - public void testAllCommand() { - testCommand("-n", "-f", "-d"); - } - - @Test - public void testAllCommandLongArgs() { - testCommand("--noninteractive", "--force", "--deletecookie"); - } - - private void testCommand(String... args) { - FormatCommand cmd = new FormatCommand(); - try { - assertTrue(cmd.apply(bkFlags, args)); - } catch (Exception e) { - e.printStackTrace(); - fail("Should not throw any exception here"); - } - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/InitCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/InitCommandTest.java deleted file mode 100644 index c627bdb20ca..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/InitCommandTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; - -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Test; - -/** - * Unit test for {@link InitCommand}. - */ -public class InitCommandTest extends BookieCommandTestBase { - - public InitCommandTest() { - super(3, 0); - } - - public void setup() throws Exception { - mockServerConfigurationConstruction(); - mockBookKeeperAdminConstruction(); - mockStatic(BookKeeperAdmin.class).when(() -> BookKeeperAdmin.initBookie(any(ServerConfiguration.class))) - .thenReturn(true); - } - - @Test - public void testInitCommand() { - InitCommand initCommand = new InitCommand(); - try { - initCommand.apply(bkFlags, new String[]{""}); - } catch (Exception e) { - fail("Should not throw any exception here."); - } - - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LastMarkCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LastMarkCommandTest.java deleted file mode 100644 index b3107653315..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LastMarkCommandTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.bookie.Journal; -import org.apache.bookkeeper.bookie.Journal.LastLogMark; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.bookie.LogMark; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link LastMarkCommand}. - */ -public class LastMarkCommandTest extends BookieCommandTestBase { - - private LastLogMark lastLogMark; - private LogMark logMark; - private static final int NUM_JOURNAL_DIRS = 3; - - public LastMarkCommandTest() { - super(NUM_JOURNAL_DIRS, 0); - } - - @Before - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(conf -> { - doReturn(0.95f).when(conf).getDiskUsageThreshold(); - }); - mockConstruction(LedgerDirsManager.class); - - this.lastLogMark = mock(LastLogMark.class); - this.logMark = mock(LogMark.class); - when(lastLogMark.getCurMark()).thenReturn(logMark); - - mockConstruction(Journal.class, (journal, context) -> { - when(journal.getLastLogMark()).thenReturn(lastLogMark); - }); - } - - @Test - public void testCommand() throws Exception { - LastMarkCommand cmd = new LastMarkCommand(); - cmd.apply(bkFlags, new String[] { "" }); - - for (int i = 0; i < NUM_JOURNAL_DIRS; i++) { - verify(getMockedConstruction(Journal.class).constructed().get(i), times(1)).getLastLogMark(); - } - - verify(lastLogMark, times(3)).getCurMark(); - verify(logMark, times(3 * 2)).getLogFileId(); - verify(logMark, times(3)).getLogFileOffset(); - } - - - - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LedgerCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LedgerCommandTest.java deleted file mode 100644 index 7d30bad0b6d..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LedgerCommandTest.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.internal.verification.VerificationModeFactory.times; - -import java.util.Iterator; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.InterleavedLedgerStorage; -import org.apache.bookkeeper.bookie.LedgerCache; -import org.apache.bookkeeper.bookie.LedgerEntryPage; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage; -import org.apache.bookkeeper.bookie.storage.ldb.SingleDirectoryDbLedgerStorage; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedStatic; - -/** - * Unit test for {@link LedgerCommand}. - */ -public class LedgerCommandTest extends BookieCommandTestBase { - - private LedgerCache.LedgerIndexMetadata metadata; - - public LedgerCommandTest() { - super(3, 0); - } - - public void setup() throws Exception { - super.setup(); - mockServerConfigurationConstruction(serverconf -> { - final ServerConfiguration defaultValue = new ServerConfiguration(); - when(serverconf.getLedgerStorageClass()).thenReturn(defaultValue.getLedgerStorageClass()); - }); - final MockedStatic dbLedgerStorageMockedStatic = mockStatic(DbLedgerStorage.class); - dbLedgerStorageMockedStatic - .when(() -> DbLedgerStorage.readLedgerIndexEntries(anyLong(), - any(ServerConfiguration.class), - any(SingleDirectoryDbLedgerStorage.LedgerLoggerProcessor.class))) - .thenAnswer(invocation -> { - SingleDirectoryDbLedgerStorage.LedgerLoggerProcessor p = invocation.getArgument(2); - p.process(1L, 1L, 1L); - return true; - }); - - - LedgerCache.PageEntries e = mock(LedgerCache.PageEntries.class); - LedgerCache.PageEntriesIterable i = mock(LedgerCache.PageEntriesIterable.class); - - metadata = mock(LedgerCache.LedgerIndexMetadata.class); - mockConstruction(InterleavedLedgerStorage.class, (interleavedLedgerStorage, context) -> { - when(interleavedLedgerStorage.getIndexEntries(anyLong())).thenReturn(i); - when(interleavedLedgerStorage.readLedgerIndexMetadata(anyLong())).thenReturn(metadata); - }); - - final MockedStatic bookieMockedStatic = mockStatic(BookieImpl.class); - bookieMockedStatic.when(() -> BookieImpl.mountLedgerStorageOffline(any(), any())) - .thenReturn(mock(LedgerStorage.class)); - - when(i.iterator()).thenReturn(getPageIterator(e)); - LedgerEntryPage lep = mock(LedgerEntryPage.class); - when(e.getLEP()).thenReturn(lep); - - - - when(metadata.getMasterKeyHex()).thenReturn(""); - } - - public Iterator getPageIterator(LedgerCache.PageEntries page) { - Iterator i = new Iterator() { - int i = 0; - - @Override - public boolean hasNext() { - if (i < 2) { - i++; - return true; - } - return false; - } - - @Override - public LedgerCache.PageEntries next() { - return page; - } - }; - return i; - } - - // Test without ledger id - @Test - public void testWithoutLedgerId() { - testLedgerCommand(""); - } - - // test ledger command without args - @Test - public void testNoArguments() { - testLedgerCommand("-id", "1"); - } - - @Test - public void testWithMeta() throws Exception { - LedgerCommand cmd = new LedgerCommand(); - cmd.apply(bkFlags, new String[] { "-id", "1", "-m" }); - - verify(metadata, times(1)).getMasterKeyHex(); - } - - @Test - public void testDbLedgerStorage() throws Exception { - - mockServerConfigurationConstruction(conf -> { - when(conf.getLedgerStorageClass()).thenReturn("org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage"); - }); - LedgerCommand cmd = new LedgerCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[]{"-id", "1"})); - } - - // test update formatter by flag - @Test - public void testFormatterFlag() { - testLedgerCommand("-id", "1", "-l", "hex"); - } - - public void testLedgerCommand(String... args) { - LedgerCommand ledgerCommand = new LedgerCommand(); - try { - ledgerCommand.apply(bkFlags, args); - } catch (IllegalArgumentException iae) { - if (!iae.getMessage().equals("No ledger id is specified")) { - Assert.fail("exception is not expect ! "); - } - } - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListFilesOnDiscCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListFilesOnDiscCommandTest.java deleted file mode 100644 index 8b0d4943702..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListFilesOnDiscCommandTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.Mockito.doReturn; - -import java.io.File; -import org.apache.bookkeeper.bookie.BookieShell; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - - -/** - * Unit test for {@link ListFilesOnDiscCommand}. - */ -public class ListFilesOnDiscCommandTest extends BookieCommandTestBase { - - public ListFilesOnDiscCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - File journals = testDir.newFolder("journals"); - journals.mkdir(); - File ledgers = testDir.newFolder("ledgers"); - ledgers.mkdir(); - File index = testDir.newFolder("index"); - index.mkdir(); - - for (int i = 0; i < 10; i++) { - File.createTempFile("journal-" + i, ".txn", journals); - File.createTempFile("ledger-" + i, ".log", ledgers); - File.createTempFile("index-" + i, ".idx", index); - } - mockServerConfigurationConstruction(conf -> { - doReturn(new String[] { index.getAbsolutePath() }).when(conf).getIndexDirNames(); - doReturn(new String[] { ledgers.getAbsolutePath() }).when(conf).getLedgerDirNames(); - doReturn(new String[] { journals.getAbsolutePath() }).when(conf).getJournalDirNames(); - }); - } - - @Test - public void testListJournalCommand() { - testCommand("-txn"); - Assert.assertEquals(10, BookieShell.listFilesAndSort( - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getJournalDirs(), "txn").size()); - } - - @Test - public void testListJournalLongCommand() { - testCommand("--journal"); - Assert.assertEquals(10, BookieShell.listFilesAndSort( - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getJournalDirs(), "txn").size()); - } - - @Test - public void testListEntryLogCommand() { - testCommand("-log"); - Assert.assertEquals(10, BookieShell.listFilesAndSort( - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getLedgerDirs(), "log").size()); - } - - @Test - public void testListEntryLogLongCommand() { - testCommand("--entrylog"); - Assert.assertEquals(10, BookieShell.listFilesAndSort( - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getLedgerDirs(), "log").size()); - } - - @Test - public void testListIndexCommand() { - testCommand("-idx"); - Assert.assertEquals(10, BookieShell.listFilesAndSort( - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getIndexDirs(), "idx").size()); - } - - @Test - public void testListIndexLongCommand() { - testCommand("--index"); - Assert.assertEquals(10, BookieShell.listFilesAndSort( - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getIndexDirs(), "idx").size()); - } - - private void testCommand(String... args) { - ListFilesOnDiscCommand cmd = new ListFilesOnDiscCommand(); - Assert.assertTrue(cmd.apply(bkFlags, args)); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListLedgersCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListLedgersCommandTest.java deleted file mode 100644 index 2d4a90fd998..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ListLedgersCommandTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.zookeeper.AsyncCallback; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for ListLedgers command. - */ -public class ListLedgersCommandTest extends BookieCommandTestBase { - - private static final BookieId bookieAddress = BookieId.parse(UUID.randomUUID().toString()); - - public ListLedgersCommandTest() { - super(3, 3); - } - - @SuppressWarnings("unchecked") - @Override - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - - mockConstruction(BookieId.class, (bookieId, context) -> { - doReturn(bookieAddress.getId()).when(bookieId).getId(); - }); - - LedgerManagerFactory mFactory = mock(LedgerManagerFactory.class); - mockMetadataDriversWithLedgerManagerFactory(mFactory); - - LedgerManager ledgerManager = mock(LedgerManager.class); - when(mFactory.newLedgerManager()).thenReturn(ledgerManager); - - mockConstruction(CountDownLatch.class); - - AsyncCallback.VoidCallback callback = mock(AsyncCallback.VoidCallback.class); - doAnswer(invocationOnMock -> { - getMockedConstruction(CountDownLatch.class).constructed().get(0).countDown(); - return null; - }).when(callback).processResult(anyInt(), anyString(), any()); - } - - @Test - public void testWithoutBookieId() { - testCommand(""); - } - - @Test - public void testWithBookieId() { - testCommand("-id", bookieAddress.getId()); - } - - private void testCommand(String... args) { - ListLedgersCommand command = new ListLedgersCommand(); - Assert.assertTrue(command.apply(bkFlags, args)); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LocalConsistencyCheckCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LocalConsistencyCheckCommandTest.java deleted file mode 100644 index 86ea8d59579..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/LocalConsistencyCheckCommandTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.List; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.LedgerStorage; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedStatic; - -/** - * Unit test for {@link LocalConsistencyCheckCommand}. - */ -public class LocalConsistencyCheckCommandTest extends BookieCommandTestBase { - - private LedgerStorage ledgerStorage; - public LocalConsistencyCheckCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - ledgerStorage = mock(LedgerStorage.class); - mockServerConfigurationConstruction(); - final MockedStatic bookieMockedStatic = mockStatic(BookieImpl.class); - bookieMockedStatic.when(() -> BookieImpl.mountLedgerStorageOffline(any(ServerConfiguration.class), eq(null))) - .thenReturn(ledgerStorage); - List errors = new ArrayList<>(); - when(ledgerStorage.localConsistencyCheck(eq(java.util.Optional.empty()))).thenReturn(errors); - } - - @Test - public void testCommand() throws Exception { - LocalConsistencyCheckCommand cmd = new LocalConsistencyCheckCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] {})); - verify(ledgerStorage, times(1)).localConsistencyCheck(eq(java.util.Optional.empty())); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommandTest.java deleted file mode 100644 index 23f46373f41..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommandTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.File; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.bookkeeper.bookie.Journal; -import org.apache.bookkeeper.bookie.LedgerDirsManager; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.util.DiskChecker; -import org.junit.Assert; -import org.junit.Test; - - -/** - * Unit test for read journal command. - */ -public class ReadJournalCommandTest extends BookieCommandTestBase { - - public ReadJournalCommandTest() { - super(3, 0); - } - - @Test - public void testWithJournalId() throws Exception { - AtomicInteger journalCount = new AtomicInteger(); - AtomicInteger ledgerDirsManagerCount = new AtomicInteger(); - AtomicInteger diskCheckerCount = new AtomicInteger(); - mockServerConfigurationConstruction(conf -> { - doReturn(new String[] {new File(journalDirsName[0]).getAbsolutePath()}).when(conf).getJournalDirNames(); - }); - mockConstruction(DiskChecker.class, (c, context) -> { - - final ServerConfiguration defaultConf = new ServerConfiguration(); - assertEquals(defaultConf.getDiskUsageThreshold(), context.arguments().get(0)); - assertEquals(defaultConf.getDiskUsageWarnThreshold(), context.arguments().get(1)); - diskCheckerCount.incrementAndGet(); - - }); - mockConstruction(LedgerDirsManager.class, (c, context) -> { - ledgerDirsManagerCount.incrementAndGet(); - }); - mockConstruction(Journal.class, (journal, context) -> { - doAnswer(invocation -> - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getJournalDirs()[0] - ).when(journal).getJournalDirectory(); - journalCount.incrementAndGet(); - }); - - testCommand("-id", "1"); - assertEquals(1, diskCheckerCount.get()); - assertEquals(1, ledgerDirsManagerCount.get()); - assertEquals(1, journalCount.get()); - } - - @Test - public void testWithFilename() throws Exception { - AtomicInteger journalCount = new AtomicInteger(); - AtomicInteger ledgerDirsManagerCount = new AtomicInteger(); - AtomicInteger diskCheckerCount = new AtomicInteger(); - mockServerConfigurationConstruction(conf -> { - doReturn(new String[] {new File(journalDirsName[0]).getAbsolutePath()}).when(conf).getJournalDirNames(); - }); - mockConstruction(DiskChecker.class, (c, context) -> { - final ServerConfiguration defaultConf = new ServerConfiguration(); - assertEquals(defaultConf.getDiskUsageThreshold(), context.arguments().get(0)); - assertEquals(defaultConf.getDiskUsageWarnThreshold(), context.arguments().get(1)); - diskCheckerCount.incrementAndGet(); - - }); - mockConstruction(LedgerDirsManager.class, (c, context) -> { - ledgerDirsManagerCount.incrementAndGet(); - }); - mockConstruction(Journal.class, (journal, context) -> { - doAnswer(invocation -> - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getJournalDirs()[0] - ).when(journal).getJournalDirectory(); - journalCount.incrementAndGet(); - }); - File file = testDir.newFile("1.txn"); - testCommand("-f", file.getAbsolutePath(), "-m"); - assertEquals(1, diskCheckerCount.get()); - assertEquals(1, ledgerDirsManagerCount.get()); - assertEquals(1, journalCount.get()); - } - - @Test - public void testWithMsg() throws Exception { - AtomicInteger journalCount = new AtomicInteger(); - AtomicInteger ledgerDirsManagerCount = new AtomicInteger(); - AtomicInteger diskCheckerCount = new AtomicInteger(); - mockServerConfigurationConstruction(); - mockConstruction(DiskChecker.class, (c, context) -> { - - final ServerConfiguration defaultConf = new ServerConfiguration(); - assertEquals(defaultConf.getDiskUsageThreshold(), context.arguments().get(0)); - assertEquals(defaultConf.getDiskUsageWarnThreshold(), context.arguments().get(1)); - diskCheckerCount.incrementAndGet(); - - }); - mockConstruction(LedgerDirsManager.class, (c, context) -> { - ledgerDirsManagerCount.incrementAndGet(); - }); - mockConstruction(Journal.class, (journal, context) -> { - doAnswer(invocation -> - getMockedConstruction(ServerConfiguration.class).constructed().get(0).getJournalDirs()[0] - ).when(journal).getJournalDirectory(); - journalCount.incrementAndGet(); - }); - testCommand("-id", "1", "-d", new File(journalDirsName[0]).getAbsolutePath()); - assertEquals(3, journalCount.get()); - assertEquals(3, ledgerDirsManagerCount.get()); - assertEquals(3, diskCheckerCount.get()); - verify(getMockedConstruction(Journal.class).constructed().get(0), times(1)).getJournalDirectory(); - } - - public void testCommand(String... args) throws Exception { - ReadJournalCommand command = new ReadJournalCommand(); - Assert.assertTrue(command.apply(bkFlags, args)); - } - - @Test - public void testWithoutArgs() { - ReadJournalCommand command = new ReadJournalCommand(); - Assert.assertFalse(command.apply(bkFlags, new String[] { "" })); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java deleted file mode 100644 index 3f80d31dba1..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.concurrent.DefaultThreadFactory; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.function.Consumer; -import lombok.SneakyThrows; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.common.util.OrderedExecutor; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.proto.BookieClientImpl; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link ReadLedgerCommand}. - */ -public class ReadLedgerCommandTest extends BookieCommandTestBase { - - private static final BookieId bookieSocketAddress = BookieId.parse("localhost:9000"); - - private LedgerHandle ledgerHandle; - private LedgerEntry entry; - private OrderedExecutor orderedExecutor; - private ScheduledExecutorService scheduledExecutorService; - - - public ReadLedgerCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - mockClientConfigurationConstruction(); - ledgerHandle = mock(LedgerHandle.class); - entry = mock(LedgerEntry.class); - orderedExecutor = mock(OrderedExecutor.class); - scheduledExecutorService = mock(ScheduledExecutorService.class); - - when(ledgerHandle.getLastAddConfirmed()).thenReturn(1L); - - List entries = new LinkedList<>(); - entries.add(entry); - when(entry.getLedgerId()).thenReturn(1L); - when(entry.getEntryId()).thenReturn(1L); - when(entry.getLength()).thenReturn(1L); - - mockBookKeeperAdminConstruction(new Consumer() { - @Override - @SneakyThrows - public void accept(BookKeeperAdmin bookKeeperAdmin) { - when(bookKeeperAdmin.getBookieAddressResolver()) - .thenReturn(BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - when(bookKeeperAdmin.openLedger(anyLong())).thenReturn(ledgerHandle); - when(bookKeeperAdmin.readEntries(anyLong(), anyLong(), anyLong())).thenReturn(entries); - } - }); - - mockConstruction(NioEventLoopGroup.class); - - - - OrderedExecutor.Builder builder = mock(OrderedExecutor.Builder.class); - mockStatic(OrderedExecutor.class).when(() -> OrderedExecutor.newBuilder()).thenReturn(builder); - - when(builder.numThreads(anyInt())).thenCallRealMethod(); - when(builder.name(anyString())).thenCallRealMethod(); - when(builder.build()).thenReturn(orderedExecutor); - - mockConstruction(DefaultThreadFactory.class); - - mockStatic(Executors.class).when(() -> Executors - .newSingleThreadScheduledExecutor(any(DefaultThreadFactory.class))) - .thenReturn(scheduledExecutorService); - - mockConstruction(BookieClientImpl.class); - - - } - - @Test - public void testWithoutBookieAddress() throws Exception { - ReadLedgerCommand cmd = new ReadLedgerCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-r" })); - verify(ledgerHandle, times(1)).getLastAddConfirmed(); - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).readEntries(anyLong(), anyLong(), anyLong()); - verify(entry, times(1)).getLedgerId(); - verify(entry, times(1)).getEntryId(); - verify(entry, times(1)).getLength(); - } - - @Test - public void testWithBookieAddress() throws Exception { - ReadLedgerCommand cmd = new ReadLedgerCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-b", bookieSocketAddress.getId() })); - Assert.assertEquals(1, getMockedConstruction(NioEventLoopGroup.class).constructed().size()); - Assert.assertEquals(1, getMockedConstruction(DefaultThreadFactory.class).constructed().size()); - Assert.assertEquals(1, getMockedConstruction(BookieClientImpl.class).constructed().size()); - verify(getMockedConstruction(NioEventLoopGroup.class).constructed().get(0), times(1)).shutdownGracefully(); - verify(orderedExecutor, times(1)).shutdown(); - verify(getMockedConstruction(BookieClientImpl.class).constructed().get(0), times(1)).close(); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogCommandTest.java deleted file mode 100644 index ec12702aac9..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogCommandTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doNothing; - -import org.apache.bookkeeper.bookie.ReadOnlyDefaultEntryLogger; -import org.apache.bookkeeper.bookie.storage.EntryLogScanner; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link ReadLogCommand}. - */ -public class ReadLogCommandTest extends BookieCommandTestBase { - - public ReadLogCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - mockConstruction(ReadOnlyDefaultEntryLogger.class, (entryLogger, context) -> { - doNothing().when(entryLogger).scanEntryLog(anyLong(), any(EntryLogScanner.class)); - }); - } - - @Test - public void testWithoutAnyFlags() { - ReadLogCommand cmd = new ReadLogCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[] {})); - } - - @Test - public void testWithEntryId() { - ReadLogCommand cmd = new ReadLogCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-li", "1" })); - } - - @Test - public void testWithEntryFilename() { - ReadLogCommand cmd = new ReadLogCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-f", "1.log" })); - } - - @Test - public void testWithErrorPos() { - ReadLogCommand cmd = new ReadLogCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[] { "-sp", "1", "-ep", "0", "-li", "1" })); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogMetadataCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogMetadataCommandTest.java deleted file mode 100644 index bc4d06c37c7..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLogMetadataCommandTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.bookie.EntryLogMetadata; -import org.apache.bookkeeper.bookie.ReadOnlyDefaultEntryLogger; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.util.collections.ConcurrentLongLongHashMap; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link ReadLogMetadataCommand}. - */ -public class ReadLogMetadataCommandTest extends BookieCommandTestBase { - - private EntryLogMetadata entryLogMetadata; - - public ReadLogMetadataCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - entryLogMetadata = mock(EntryLogMetadata.class); - - mockConstruction(ReadOnlyDefaultEntryLogger.class, (entryLogger, context) -> { - when(entryLogger.getEntryLogMetadata(anyLong())).thenReturn(entryLogMetadata); - }); - - ConcurrentLongLongHashMap map = ConcurrentLongLongHashMap.newBuilder().build(); - map.put(1, 1); - when(entryLogMetadata.getLedgersMap()).thenReturn(map); - - } - - @Test - public void testWithoutFlags() { - ReadLogMetadataCommand cmd = new ReadLogMetadataCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[] {"-l", "-1", "-f", ""})); - } - - @Test - public void commandTest() throws Exception { - ReadLogMetadataCommand cmd = new ReadLogMetadataCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-l", "1" })); - verify(getMockedConstruction(ReadOnlyDefaultEntryLogger.class).constructed().get(0), times(1)) - .getEntryLogMetadata(anyLong()); - verify(entryLogMetadata, times(1)).getLedgersMap(); - } -} - diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RebuildDBLedgerLocationsIndexCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RebuildDBLedgerLocationsIndexCommandTest.java deleted file mode 100644 index 6cd688e2ff3..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RebuildDBLedgerLocationsIndexCommandTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.apache.bookkeeper.bookie.storage.ldb.LocationsIndexRebuildOp; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link RebuildDBLedgerLocationsIndexCommand}. - */ -public class RebuildDBLedgerLocationsIndexCommandTest extends BookieCommandTestBase { - - public RebuildDBLedgerLocationsIndexCommandTest() { - super(3, 0); - } - - @Test - public void testCommand() throws Exception { - mockServerConfigurationConstruction(); - mockConstruction(LocationsIndexRebuildOp.class); - - RebuildDBLedgerLocationsIndexCommand command = new RebuildDBLedgerLocationsIndexCommand(); - Assert.assertTrue(command.apply(bkFlags, new String[] { "" })); - - verify(getMockedConstruction(LocationsIndexRebuildOp.class).constructed().get(0), - times(1)).initiate(); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RegenerateInterleavedStorageIndexFileCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RegenerateInterleavedStorageIndexFileCommandTest.java deleted file mode 100644 index ce603f5caf1..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/RegenerateInterleavedStorageIndexFileCommandTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.apache.bookkeeper.bookie.InterleavedStorageRegenerateIndexOp; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link RegenerateInterleavedStorageIndexFileCommand}. - */ -public class RegenerateInterleavedStorageIndexFileCommandTest extends BookieCommandTestBase { - - public RegenerateInterleavedStorageIndexFileCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - mockServerConfigurationConstruction(); - } - - @Test - public void testCommand() throws Exception { - String ledgerIds = "1,2,3"; - String password = "12345"; - - mockConstruction(InterleavedStorageRegenerateIndexOp.class, (op, context) -> { - doNothing().when(op).initiate(anyBoolean()); - }); - RegenerateInterleavedStorageIndexFileCommand cmd = new RegenerateInterleavedStorageIndexFileCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-p", password, "-l", ledgerIds })); - verify(getMockedConstruction(InterleavedStorageRegenerateIndexOp.class).constructed().get(0), - times(1)).initiate(anyBoolean()); - } -} - diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/SanityTestCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/SanityTestCommandTest.java deleted file mode 100644 index cac5f5633ac..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/SanityTestCommandTest.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static junit.framework.TestCase.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.util.concurrent.UncheckedExecutionException; -import java.util.Enumeration; -import java.util.Vector; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.bookie.LocalBookieEnsemblePlacementPolicy; -import org.apache.bookkeeper.client.AsyncCallback.AddCallback; -import org.apache.bookkeeper.client.AsyncCallback.CreateCallback; -import org.apache.bookkeeper.client.AsyncCallback.DeleteCallback; -import org.apache.bookkeeper.client.AsyncCallback.OpenCallback; -import org.apache.bookkeeper.client.AsyncCallback.ReadCallback; -import org.apache.bookkeeper.client.BKException; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.LedgerEntry; -import org.apache.bookkeeper.client.LedgerHandle; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.commons.configuration.Configuration; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -/** - * Test for sanity command. - */ -public class SanityTestCommandTest extends BookieCommandTestBase { - - private LedgerHandle lh; - - public SanityTestCommandTest() { - super(3, 1); - } - - @Override - public void setup() throws Exception { - super.setup(); - - lh = mock(LedgerHandle.class); - mockClientConfigurationConstruction(); - mockConstruction(BookKeeper.class, (bk, context) -> { - doAnswer(new Answer() { - public Void answer(InvocationOnMock invocation) { - ((CreateCallback) invocation.getArguments()[4]).createComplete(BKException.Code.OK, lh, - null); - return null; - } - }).when(bk).asyncCreateLedger(anyInt(), anyInt(), any(BookKeeper.DigestType.class), eq(new byte[0]), - any(CreateCallback.class), any()); - doAnswer(new Answer() { - public Void answer(InvocationOnMock invocation) { - ((OpenCallback) invocation.getArguments()[3]).openComplete(BKException.Code.OK, lh, - null); - return null; - } - }).when(bk).asyncOpenLedger(anyLong(), any(BookKeeper.DigestType.class), eq(new byte[0]), - any(OpenCallback.class), any()); - }); - when(lh.closeAsync()).thenReturn(CompletableFuture.completedFuture(null)); - when(lh.getLastAddConfirmed()).thenReturn(9L); - Enumeration entryEnumeration = getEntry(); - when(lh.getId()).thenReturn(1L); - - doAnswer(new Answer() { - public Void answer(InvocationOnMock invocation) { - ((ReadCallback) invocation.getArguments()[2]).readComplete(BKException.Code.OK, lh, - entryEnumeration, null); - return null; - } - }).when(lh).asyncReadEntries(anyLong(), anyLong(), any(ReadCallback.class), any()); - doAnswer(new Answer() { - public Void answer(InvocationOnMock invocation) { - ((AddCallback) invocation.getArguments()[1]).addComplete(BKException.Code.OK, lh, - 0, null); - return null; - } - }).when(lh).asyncAddEntry(any(byte[].class), any(AddCallback.class), any()); - } - - private Enumeration getEntry() { - Vector entries = new Vector<>(); - for (int i = 0; i < 10; i++) { - LedgerEntry ledgerEntry = mock(LedgerEntry.class); - String payload = "entry-" + i; - when(ledgerEntry.getEntry()).thenReturn(payload.getBytes(UTF_8)); - entries.add(ledgerEntry); - } - return entries.elements(); - } - - @Test - public void testDefaultArgs() { - testSanityCommand(""); - } - - @Test - public void testEntriesShortArgs() { - when(lh.getLastAddConfirmed()).thenReturn(0L); - testSanityCommand("-e", "1"); - verifyFunc(); - } - - @Test - public void testEntriesLongArgs() { - when(lh.getLastAddConfirmed()).thenReturn(0L); - testSanityCommand("--entries", "1"); - verifyFunc(); - } - - private void verifyFunc() { - try { - final ClientConfiguration clientConf = - getMockedConstruction(ClientConfiguration.class).constructed().get(0); - verify(clientConf, times(1)).setAddEntryTimeout(1); - verify(clientConf, times(1)).setReadEntryTimeout(1); - verify(lh, times(1)).asyncAddEntry(any(byte[].class), any(AddCallback.class), any()); - verify(lh, times(1)).asyncReadEntries(eq(0L), eq(0L), any(ReadCallback.class), any()); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - } - - @Test - public void testTimeoutShortArgs() { - testSanityCommand("-t", "10"); - } - - @Test - public void testTimeoutLongArgs() { - testSanityCommand("--timeout", "10"); - } - - public void testSanityCommand(String... args) { - SanityTestCommand cmd = new SanityTestCommand(); - assertTrue(cmd.apply(bkFlags, args)); - try { - final ClientConfiguration clientConf = - getMockedConstruction(ClientConfiguration.class).constructed().get(0); - verify(clientConf, times(1)) - .addConfiguration(any(Configuration.class)); - verify(clientConf, times(1)) - .setEnsemblePlacementPolicy(LocalBookieEnsemblePlacementPolicy.class); - final BookKeeper bk = getMockedConstruction(BookKeeper.class).constructed().get(0); - verify(bk, times(1)).asyncCreateLedger(eq(1), eq(1), eq(BookKeeper.DigestType.MAC), eq(new byte[0]), - any(CreateCallback.class), any()); - verify(bk, times(1)).asyncOpenLedger(anyLong(), eq(BookKeeper.DigestType.MAC), eq(new byte[0]), - any(OpenCallback.class), any()); - verify(lh, times(1)).getLastAddConfirmed(); - verify(bk, times(1)).asyncDeleteLedger(anyLong(), any(DeleteCallback.class), any()); - } catch (Exception e) { - throw new UncheckedExecutionException(e.getMessage(), e); - } - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/DecommissionCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/DecommissionCommandTest.java deleted file mode 100644 index 829198ba23b..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/DecommissionCommandTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.UUID; -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedStatic; - -/** - * Unit test for {@link DecommissionCommand}. - */ -@SuppressWarnings("unchecked") -public class DecommissionCommandTest extends BookieCommandTestBase { - - private Versioned cookieVersioned; - private static final String bookieID = UUID.randomUUID().toString(); - - public DecommissionCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - - mockServerConfigurationConstruction(conf -> { - doReturn(bookieID).when(conf).getBookieId(); - }); - mockClientConfigurationConstruction(); - mockBookKeeperAdminConstruction(); - mockConstruction(BookieId.class, (mocked, context) -> { - doReturn(bookieID).when(mocked).getId(); - }); - - RegistrationManager registrationManager = mock(RegistrationManager.class); - mockMetadataDriversWithRegistrationManager(registrationManager); - - - cookieVersioned = mock(Versioned.class); - final MockedStatic cookieMockedStatic = mockStatic(Cookie.class); - cookieMockedStatic.when(() -> Cookie.readFromRegistrationManager(eq(registrationManager), - any(BookieId.class))) - .thenReturn(cookieVersioned); - - final Cookie cookie = mock(Cookie.class); - final Version version = mock(Version.class); - - when(cookieVersioned.getValue()).thenReturn(cookie); - when(cookieVersioned.getVersion()).thenReturn(version); - doNothing().when(cookie) - .deleteFromRegistrationManager(eq(registrationManager), any(BookieId.class), eq(version)); - } - - @Test - public void testWithoutBookieId() throws Exception { - DecommissionCommand cmd = new DecommissionCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).decommissionBookie(any(BookieId.class)); - verify(cookieVersioned, times(1)).getValue(); - verify(cookieVersioned, times(1)).getVersion(); - } - - @Test - public void testWithBookieId() throws Exception { - DecommissionCommand cmd = new DecommissionCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-b", bookieID })); - - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).decommissionBookie(any(BookieId.class)); - verify(cookieVersioned, times(1)).getValue(); - verify(cookieVersioned, times(1)).getVersion(); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InfoCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InfoCommandTest.java deleted file mode 100644 index c7bcaee8db1..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InfoCommandTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.Map; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.client.BookieInfoReader; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.net.BookieSocketAddress; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Before; -import org.junit.Test; -/** - * Unit test of {@link InfoCommand}. - */ -public class InfoCommandTest extends BookieCommandTestBase { - - private BookieId bookieId; - private BookieInfoReader.BookieInfo bInfo; - private Map map = new HashMap<>(); - - public InfoCommandTest() { - super(1, 0); - } - - @Before - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - mockClientConfigurationConstruction(); - - this.bookieId = BookieId.parse("localhost:9999"); - this.bInfo = mock(BookieInfoReader.BookieInfo.class); - map.put(bookieId, bInfo); - - mockConstruction(BookKeeper.class, (bk, context) -> { - when(bk.getBookieAddressResolver()).thenReturn(BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); - when(bk.getBookieInfo()).thenReturn(map); - }); - } - - @Test - public void testCommand() throws Exception { - InfoCommand cmd = new InfoCommand(); - cmd.apply(bkFlags, new String[]{""}); - - verify(getMockedConstruction(BookKeeper.class).constructed().get(0), times(1)).getBookieInfo(); - verify(bInfo, times(1 * 3)).getFreeDiskSpace(); - verify(bInfo, times(1 * 3)).getTotalDiskSpace(); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InitCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InitCommandTest.java deleted file mode 100644 index 75caf11c79e..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InitCommandTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.mockito.ArgumentMatchers.any; - -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedStatic; - -/** - * Unit test for {@link InitCommand}. - */ -public class InitCommandTest extends BookieCommandTestBase { - - public InitCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - mockServerConfigurationConstruction(); - final MockedStatic bookKeeperAdminMockedStatic = mockStatic(BookKeeperAdmin.class); - bookKeeperAdminMockedStatic.when(() -> BookKeeperAdmin.initNewCluster(any(ServerConfiguration.class))) - .thenReturn(true); - } - - @Test - public void testCommand() { - InitCommand initCommand = new InitCommand(); - Assert.assertTrue(initCommand.apply(bkFlags, new String[] {})); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InstanceIdCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InstanceIdCommandTest.java deleted file mode 100644 index c3bd3d5a667..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/InstanceIdCommandTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link InstanceIdCommand}. - */ -public class InstanceIdCommandTest extends BookieCommandTestBase { - - public InstanceIdCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - final RegistrationManager manager = mock(RegistrationManager.class); - mockMetadataDriversWithRegistrationManager(manager); - when(manager.getClusterInstanceId()).thenReturn(""); - } - - @Test - public void testCommand() { - InstanceIdCommand cmd = new InstanceIdCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] {})); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/ListBookiesCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/ListBookiesCommandTest.java deleted file mode 100644 index 5f661427d73..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/ListBookiesCommandTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.apache.bookkeeper.common.concurrent.FutureUtils.value; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.withSettings; - -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeSet; -import org.apache.bookkeeper.discover.BookieServiceInfoUtils; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.proto.BookieAddressResolver; -import org.apache.bookkeeper.tools.cli.helpers.CommandHelpers; -import org.apache.bookkeeper.tools.cli.helpers.DiscoveryCommandTestBase; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link ListBookiesCommand}. - */ -public class ListBookiesCommandTest extends DiscoveryCommandTestBase { - - private static class BookieAddressComparator implements Comparator { - - @Override - public int compare(BookieId o1, BookieId o2) { - return o1.toString().compareToIgnoreCase(o2.toString()); - } - } - - private Set writableBookies; - private Set readonlyBookies; - private Set allBookies; - - @Before - public void setup() throws Exception { - super.setup(); - - writableBookies = createBookies(3181, 10); - readonlyBookies = createBookies(4181, 10); - - allBookies = new HashSet<>(); - allBookies.addAll(writableBookies); - allBookies.addAll(readonlyBookies); - - when(regClient.getWritableBookies()) - .thenReturn(value(new Versioned<>(writableBookies, new LongVersion(0L)))); - when(regClient.getBookieServiceInfo(any(BookieId.class))) - .thenReturn(value(new Versioned<>( - BookieServiceInfoUtils.buildLegacyBookieServiceInfo("localhost:1234"), new LongVersion(0)))); - when(regClient.getReadOnlyBookies()) - .thenReturn(value(new Versioned<>(readonlyBookies, new LongVersion(0L)))); - when(regClient.getAllBookies()) - .thenReturn(value(new Versioned<>(allBookies, new LongVersion(0L)))); - - mockStatic(CommandHelpers.class, withSettings().defaultAnswer(CALLS_REAL_METHODS)); - } - - private static Set createBookies(int startPort, int numBookies) { - Set bookies = new TreeSet<>(new BookieAddressComparator()); - int i = 0; - for (; i < numBookies - 1; i++) { - bookies.add(BookieId.parse("127.0.0.1" + (startPort + i))); - } - // mix an unknown hostname bookieId - bookies.add(BookieId.parse("unknown" + (startPort + i))); - return bookies; - } - - private void verifyPrintBookies(int startPort, int numBookies, int numCalls) { - for (int i = 0; i < numBookies; i++) { - if (i == numBookies - 1){ - final BookieId expectedBookieId = BookieId.parse("unknown" + (startPort + i)); - getMockedStatic(CommandHelpers.class) - .verify(() -> CommandHelpers.getBookieSocketAddrStringRepresentation( - eq(expectedBookieId), - any(BookieAddressResolver.class)), - times(numCalls)); - } else { - final BookieId expectedBookieId = BookieId.parse("127.0.0.1" + (startPort + i)); - getMockedStatic(CommandHelpers.class) - .verify(() -> CommandHelpers.getBookieSocketAddrStringRepresentation( - eq(expectedBookieId), - any(BookieAddressResolver.class)), - times(numCalls)); - } - } - } - - @Test - public void testListReadWriteShortArgs() { - testCommand(false, true, false, - "list", - "-rw"); - } - - @Test - public void testListReadWriteLongArgs() { - testCommand(false, true, false, - "list", - "--readwrite"); - } - - @Test - public void testListReadOnlyShortArgs() { - testCommand(false, false, true, - "list", - "-ro"); - } - - @Test - public void testListAllLongArgs() { - testCommand(true, false, false, - "list", - "--all"); - } - - @Test - public void testListAllShortArgs() { - testCommand(true, false, false, - "list", - "-a"); - } - - @Test - public void testListReadOnlyLongArgs() { - testCommand(false, false, true, - "list", - "--readonly"); - } - - @Test - public void testListNoArgs() { - testCommand(true, true, true, - "list"); - } - - @Test - public void testListTwoFlagsCoexistsShortArgs() { - testCommand(false, true, true, - "list", "-rw", "-ro"); - } - - @Test - public void testListTwoFlagsCoexistsLongArgs() { - testCommand(false, true, true, - "list", "--readwrite", "--readonly"); - } - - private void testCommand(boolean all, - boolean readwrite, - boolean readonly, - String... args) { - - ListBookiesCommand cmd = new ListBookiesCommand(); - try { - assertTrue(cmd.apply(bkFlags, args)); - } catch (Exception e) { - e.printStackTrace(); - fail("Should not throw any exception here"); - } - - if (all) { - if (readwrite && readonly) { - verifyPrintBookies(3181, 10, 2); - verifyPrintBookies(4181, 10, 2); - } else if (readwrite && !readonly) { - verifyPrintBookies(3181, 10, 2); - verifyPrintBookies(4181, 10, 1); - } else if (readonly && !readwrite) { - verifyPrintBookies(3181, 10, 1); - verifyPrintBookies(4181, 10, 2); - } else { - verifyPrintBookies(3181, 10, 1); - verifyPrintBookies(4181, 10, 1); - } - } else if (readwrite && !readonly) { - verifyPrintBookies(3181, 10, 1); - verifyPrintBookies(4181, 10, 0); - } else if (readonly && !readwrite) { - verifyPrintBookies(3181, 10, 0); - verifyPrintBookies(4181, 10, 1); - } else { - verifyPrintBookies(3181, 10, 1); - verifyPrintBookies(4181, 10, 1); - } - } - - @Test - public void testListEmptyBookies() throws Exception { - // overwrite regClient to return empty bookies - when(regClient.getWritableBookies()) - .thenReturn(value(new Versioned<>(Collections.emptySet(), new LongVersion(0L)))); - when(regClient.getReadOnlyBookies()) - .thenReturn(value(new Versioned<>(Collections.emptySet(), new LongVersion(0L)))); - - ListBookiesCommand cmd = new ListBookiesCommand(); - assertTrue(cmd.apply(bkFlags, new String[] { "-rw"})); - - getMockedStatic(CommandHelpers.class) - .verify(() -> CommandHelpers.getBookieSocketAddrStringRepresentation(any(), any()), - times(0)); - - assertTrue(cmd.apply(bkFlags, new String[]{"-ro"})); - - getMockedStatic(CommandHelpers.class) - .verify(() -> CommandHelpers.getBookieSocketAddrStringRepresentation(any(), any()), - times(0)); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/MetaFormatCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/MetaFormatCommandTest.java deleted file mode 100644 index d702576627e..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/MetaFormatCommandTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; - -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedStatic; - -/** - * Unit test for {@link MetaFormatCommand}. - */ -public class MetaFormatCommandTest extends BookieCommandTestBase { - - public MetaFormatCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - final MockedStatic bookKeeperAdminMockedStatic = mockStatic(BookKeeperAdmin.class); - bookKeeperAdminMockedStatic.when(() -> BookKeeperAdmin.format(any(ServerConfiguration.class), - anyBoolean(), anyBoolean())).thenReturn(true); - - } - - @Test - public void testCommand() { - MetaFormatCommand cmd = new MetaFormatCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "" })); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/NukeExistingClusterCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/NukeExistingClusterCommandTest.java deleted file mode 100644 index 929f6d396bc..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/NukeExistingClusterCommandTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; - -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link NukeExistingClusterCommand}. - */ -public class NukeExistingClusterCommandTest extends BookieCommandTestBase { - - public NukeExistingClusterCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - - } - - @Test - public void commandWithoutFlags() throws Exception { - NukeExistingClusterCommand cmd = new NukeExistingClusterCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[] { "" })); - } - - @Test - public void commandWithoutForceAndInstanceId() { - NukeExistingClusterCommand cmd = new NukeExistingClusterCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[] { "-p", "" })); - } - - @Test - public void testCommand() throws Exception { - mockStatic(BookKeeperAdmin.class).when(() -> - BookKeeperAdmin.nukeExistingCluster(any(ServerConfiguration.class), anyString(), anyString(), anyBoolean())) - .thenReturn(true); - - NukeExistingClusterCommand cmd = new NukeExistingClusterCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-p", "", "-i", "1" })); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/RecoverCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/RecoverCommandTest.java deleted file mode 100644 index 4c0524cca31..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookies/RecoverCommandTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.bookies; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.internal.verification.VerificationModeFactory.times; - -import com.google.common.collect.ImmutableList; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NavigableMap; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.function.Consumer; -import lombok.SneakyThrows; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link RecoverCommand}. - */ -@SuppressWarnings("unchecked") -public class RecoverCommandTest extends BookieCommandTestBase { - - private static final BookieId bookieSocketAddress = BookieId.parse("127.0.0.1:8000"); - - private LedgerMetadata ledgerMetadata; - private RegistrationManager registrationManager; - private Versioned cookieVersioned; - - public RecoverCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - mockServerConfigurationConstruction(); - mockClientConfigurationConstruction(); - ledgerMetadata = mock(LedgerMetadata.class); - registrationManager = mock(RegistrationManager.class); - cookieVersioned = mock(Versioned.class); - - - mockBkQuery(); - mockDeleteCookie(); - mockDeleteCookies(); - } - - private void mockBkQuery() { - SortedMap ledgerMetadataSortedMap = new TreeMap<>(); - ledgerMetadataSortedMap.put(1L, ledgerMetadata); - - mockBookKeeperAdminConstruction(new Consumer() { - @Override - @SneakyThrows - public void accept(BookKeeperAdmin bookKeeperAdmin) { - when(bookKeeperAdmin.getLedgersContainBookies(any())).thenReturn(ledgerMetadataSortedMap); - doNothing().when(bookKeeperAdmin).recoverBookieData(any(), anyBoolean(), anyBoolean()); - when(bookKeeperAdmin.getConf()).thenAnswer(i -> - getMockedConstruction(ClientConfiguration.class).constructed().get(0)); - } - }); - - ArrayList arrayList = new ArrayList<>(); - arrayList.add(bookieSocketAddress); - Map> map = new HashMap<>(); - map.put(1L, arrayList); - NavigableMap> navigableMap = Collections.unmodifiableNavigableMap( - map.entrySet().stream() - .collect(TreeMap::new, (m, e) -> m.put(e.getKey(), ImmutableList.copyOf(e.getValue())), - TreeMap::putAll)); - doReturn(navigableMap).when(ledgerMetadata).getAllEnsembles(); - } - - - - private void mockDeleteCookies() throws Exception { - mockMetadataDriversWithRegistrationManager(registrationManager); - } - - private void mockDeleteCookie() throws BookieException { - mockStatic(Cookie.class).when(() -> Cookie.readFromRegistrationManager(eq(registrationManager), - eq(bookieSocketAddress))) - .thenReturn(cookieVersioned); - Cookie cookie = mock(Cookie.class); - when(cookieVersioned.getValue()).thenReturn(cookie); - Version version = mock(Version.class); - when(cookieVersioned.getVersion()).thenReturn(version); - doNothing().when(cookie) - .deleteFromRegistrationManager(eq(registrationManager), eq(bookieSocketAddress), eq(version)); - } - - @Test - public void testBookieListCheck() { - RecoverCommand cmd = new RecoverCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[] { "-bs", "127.0.0.1:8000,$nonvalidbookieid:8001" })); - } - - @Test - public void testQuery() throws Exception { - RecoverCommand cmd = new RecoverCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-q", "-bs", "127.0.0.1:8000", "-f" })); - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).getLedgersContainBookies(any()); - } - - @Test - public void testLedgerId() throws Exception { - RecoverCommand cmd = new RecoverCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-bs", "127.0.0.1:8000", "-f", "-l", "1" })); - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), times(1)) - .recoverBookieData(anyLong(), any(), anyBoolean(), anyBoolean()); - } - - @Test - public void testWithLedgerIdAndRemoveCookies() throws Exception { - RecoverCommand cmd = new RecoverCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-bs", "127.0.0.1:8000", "-f", "-l", "1", "-d" })); - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).recoverBookieData(anyLong(), any(), anyBoolean(), anyBoolean()); - verify(getMockedConstruction(BookKeeperAdmin.class).constructed().get(0), - times(1)).getConf(); - verify(cookieVersioned, times(1)).getValue(); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/DeleteLedgerCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/DeleteLedgerCommandTest.java deleted file mode 100644 index cb31b110767..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/DeleteLedgerCommandTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.client; - -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.bookkeeper.client.BookKeeper; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.util.IOUtils; -import org.apache.commons.configuration.Configuration; -import org.junit.Test; - - -/** - * Unit test for {@link DeleteLedgerCommand}. - */ -public class DeleteLedgerCommandTest extends BookieCommandTestBase { - - public DeleteLedgerCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - - - mockStatic(IOUtils.class); - } - - @Test - public void testCommandWithoutForce() throws Exception { - getMockedStatic(IOUtils.class).when(() -> IOUtils.confirmPrompt(anyString())).thenReturn(false); - mockClientConfigurationConstruction(conf -> { - doThrow(new RuntimeException("unexpected call")).when(conf).addConfiguration(any(Configuration.class)); - }); - - mockConstruction(BookKeeper.class, (bk, context) -> { - throw new RuntimeException("unexpected call"); - }); - - DeleteLedgerCommand cmd = new DeleteLedgerCommand(); - assertTrue(cmd.apply(bkFlags, new String[] { "-l", "1" })); - assertTrue(getMockedConstruction(BookKeeper.class).constructed().isEmpty()); - } - - @Test - public void testCommandWithForce() throws Exception { - AtomicBoolean calledAddConf = new AtomicBoolean(); - mockClientConfigurationConstruction(conf -> { - doAnswer(invocation -> { - calledAddConf.set(true); - return conf; - }).when(conf).addConfiguration(any(Configuration.class)); - }); - - mockConstruction(BookKeeper.class, (bk, context) -> { - doNothing().when(bk).deleteLedger(anyLong()); - doNothing().when(bk).close(); - }); - - DeleteLedgerCommand cmd = new DeleteLedgerCommand(); - assertTrue(cmd.apply(bkFlags, new String[] { "-l", "1", "-f" })); - - assertTrue(calledAddConf.get()); - verify(getMockedConstruction(BookKeeper.class).constructed().get(0), times(1)).deleteLedger(1); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/LedgerMetaDataCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/LedgerMetaDataCommandTest.java deleted file mode 100644 index 5d0eee5a34a..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/LedgerMetaDataCommandTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.client; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.IOException; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import org.apache.bookkeeper.client.BKException.BKLedgerExistException; -import org.apache.bookkeeper.client.api.LedgerMetadata; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.meta.LedgerManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.LedgerMetadataSerDe; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for {@link LedgerMetaDataCommand}. - */ -@SuppressWarnings("unchecked") -public class LedgerMetaDataCommandTest extends BookieCommandTestBase { - - private LedgerManager ledgerManager; - private LedgerManagerFactory factory; - private CompletableFuture> future; - - - public LedgerMetaDataCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - factory = mock(LedgerManagerFactory.class); - - mockMetadataDriversWithLedgerManagerFactory(factory); - ledgerManager = mock(LedgerManager.class); - when(factory.newLedgerManager()).thenReturn(ledgerManager); - - LedgerMetadata ledgerMetadata = mock(LedgerMetadata.class); - when(ledgerMetadata.getMetadataFormatVersion()).thenReturn(1); - Versioned versioned = new Versioned(ledgerMetadata, Version.NEW); - versioned.setValue(ledgerMetadata); - CompletableFuture> future = mock(CompletableFuture.class); - when(future.join()).thenReturn(versioned); - when(ledgerManager.readLedgerMetadata(anyLong())).thenReturn(future); - when(ledgerManager.readLedgerMetadata(anyLong())).thenReturn(future); - when(future.get()).thenReturn(versioned); - - mockConstruction(LedgerMetadataSerDe.class, (serDe, context) -> { - when(serDe.serialize(eq(ledgerMetadata))).thenReturn(new byte[0]); - when(serDe.parseConfig(eq(new byte[0]), anyLong(), eq(Optional.empty()))).thenReturn(ledgerMetadata); - }); - - when(ledgerManager.createLedgerMetadata(anyLong(), eq(ledgerMetadata))).thenReturn(future); - when(ledgerManager.writeLedgerMetadata(anyLong(), eq(ledgerMetadata), any())).thenReturn(future); - } - - @Test - public void testWithDumpToFile() throws IOException { - File file = testDir.newFile("testdump"); - LedgerMetaDataCommand cmd = new LedgerMetaDataCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-l", "1", "-d", file.getAbsolutePath() })); - - verify(ledgerManager, times(1)).readLedgerMetadata(anyLong()); - verify(getMockedConstruction(LedgerMetadataSerDe.class).constructed().get(0), - times(1)).serialize(any(LedgerMetadata.class)); - } - - @Test - public void testWithRestoreFromFile() throws IOException { - File file = testDir.newFile("testrestore"); - LedgerMetaDataCommand cmd = new LedgerMetaDataCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-l", "1", "-r", file.getAbsolutePath() })); - - verify(getMockedConstruction(LedgerMetadataSerDe.class).constructed().get(0), - times(1)).parseConfig(eq(new byte[0]), anyLong(), eq(Optional.empty())); - verify(ledgerManager, times(1)).createLedgerMetadata(anyLong(), any(LedgerMetadata.class)); - } - - @Test - public void testWithoutArgs() { - LedgerMetaDataCommand cmd = new LedgerMetaDataCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-l", "1" })); - - verify(factory, times(1)).newLedgerManager(); - verify(ledgerManager, times(1)).readLedgerMetadata(anyLong()); - } - - @Test - public void testWithRestoreFromFileWithExistingLedger() throws IOException { - when(ledgerManager.createLedgerMetadata(anyLong(), any())) - .thenReturn(FutureUtils.exception(new BKLedgerExistException())); - File file = testDir.newFile("testrestore"); - LedgerMetaDataCommand cmd = new LedgerMetaDataCommand(); - Assert.assertTrue(cmd.apply(bkFlags, new String[] { "-l", "1", "-u", "-r", file.getAbsolutePath() })); - - verify(ledgerManager, times(1)).createLedgerMetadata(anyLong(), any(LedgerMetadata.class)); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/SimpleTestCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/SimpleTestCommandTest.java deleted file mode 100644 index 70ffa46f00d..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/client/SimpleTestCommandTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.client; - -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Collectors; -import org.apache.bookkeeper.client.api.CreateBuilder; -import org.apache.bookkeeper.client.api.DeleteBuilder; -import org.apache.bookkeeper.client.api.DigestType; -import org.apache.bookkeeper.client.api.LedgerEntry; -import org.apache.bookkeeper.client.api.OpenBuilder; -import org.apache.bookkeeper.client.api.ReadHandle; -import org.apache.bookkeeper.client.api.WriteHandle; -import org.apache.bookkeeper.client.impl.LedgerEntriesImpl; -import org.apache.bookkeeper.client.impl.LedgerEntryImpl; -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.tools.cli.helpers.ClientCommandTestBase; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -/** - * Unit test of {@link SimpleTestCommand}. - */ -public class SimpleTestCommandTest extends ClientCommandTestBase { - - @Test - public void testCommandShortArgs() throws Exception { - testCommand( - "-e", "5", - "-w", "3", - "-a", "3", - "-n", "10"); - } - - @Test - public void testCommandLongArgs() throws Exception { - testCommand( - "--ensemble-size", "5", - "--write-quorum-size", "3", - "--ack-quorum-size", "3", - "--num-entries", "10"); - } - - @SuppressWarnings("unchecked") - public void testCommand(String... args) throws Exception { - WriteHandle wh = mock(WriteHandle.class); - AtomicLong counter = new AtomicLong(0L); - CreateBuilder createBuilder = mock(CreateBuilder.class); - when(createBuilder.execute()).thenReturn(FutureUtils.value(wh)); - when(createBuilder.withEnsembleSize(anyInt())).thenReturn(createBuilder); - when(createBuilder.withCustomMetadata(any())).thenReturn(createBuilder); - when(createBuilder.withWriteQuorumSize(anyInt())).thenReturn(createBuilder); - when(createBuilder.withAckQuorumSize(anyInt())).thenReturn(createBuilder); - when(createBuilder.withDigestType(any(DigestType.class))).thenReturn(createBuilder); - when(createBuilder.withPassword(any(byte[].class))).thenReturn(createBuilder); - when(createBuilder.execute()).thenReturn(CompletableFuture.completedFuture(wh)); - when(mockBk.newCreateLedgerOp()).thenReturn(createBuilder); - long ledgerId = 1234L; - when(wh.getId()).thenReturn(ledgerId); - when(wh.getLastAddPushed()).then(__ -> counter.get() - 1L); - List entries = new ArrayList<>(); - byte[] data = new byte[100]; // test data - Random random = new Random(0); - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (random.nextInt(26) + 65); - } - when(wh.append(any(byte[].class))).then(invocation -> { - long entryId = counter.getAndIncrement(); - ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.heapBuffer(100); - buffer.writeBytes(data); - entries.add(LedgerEntryImpl.create(ledgerId, entryId, data.length, buffer)); - return entryId; - }); - ReadHandle rh = mock(ReadHandle.class); - when(rh.read(anyLong(), anyLong())).then( - __ -> LedgerEntriesImpl.create(entries.stream() - .map(LedgerEntry::duplicate).collect(Collectors.toList()))); - when(rh.readUnconfirmed(anyLong(), anyLong())).then( - __ -> LedgerEntriesImpl.create(entries.stream() - .map(LedgerEntry::duplicate).collect(Collectors.toList()))); - OpenBuilder openBuilder = mock(OpenBuilder.class); - when(openBuilder.withLedgerId(anyLong())).thenReturn(openBuilder); - when(openBuilder.withDigestType(any())).thenReturn(openBuilder); - when(openBuilder.withPassword(any())).thenReturn(openBuilder); - when(openBuilder.execute()).thenReturn(CompletableFuture.completedFuture(rh)); - when(mockBk.newOpenLedgerOp()).thenReturn(openBuilder); - - DeleteBuilder deleteBuilder = mock(DeleteBuilder.class); - when(deleteBuilder.withLedgerId(anyLong())).thenReturn(deleteBuilder); - when(deleteBuilder.execute()).thenReturn(CompletableFuture.completedFuture(null)); - when(mockBk.newDeleteLedgerOp()).thenReturn(deleteBuilder); - - SimpleTestCommand cmd = new SimpleTestCommand(); - cmd.apply(bkFlags, args); - - // verify create builder - ArgumentCaptor mapArgumentCaptor = ArgumentCaptor.forClass(Map.class); - verify(createBuilder, times(1)).withEnsembleSize(eq(5)); - verify(createBuilder, times(1)).withWriteQuorumSize(eq(3)); - verify(createBuilder, times(1)).withAckQuorumSize(eq(3)); - verify(createBuilder, times(1)).withCustomMetadata(mapArgumentCaptor.capture()); - assertTrue(Arrays.equals((byte[]) mapArgumentCaptor.getValue().get("Bookie"), - "simpletest".getBytes(StandardCharsets.UTF_8))); - verify(createBuilder, times(1)).withDigestType(eq(DigestType.CRC32C)); - verify(createBuilder, times(1)).withPassword(eq(new byte[0])); - verify(createBuilder, times(1)).execute(); - - verify(openBuilder, times(2)).withLedgerId(eq(1234L)); - verify(openBuilder, times(2)).execute(); - - verify(deleteBuilder, times(1)).withLedgerId(eq(1234L)); - verify(deleteBuilder, times(1)).execute(); - - // verify appends - verify(wh, times(10)).append(eq(data)); - - verify(rh, times(1)).read(anyLong(), anyLong()); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommandTest.java deleted file mode 100644 index 50f274d17ee..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommandTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.cookie; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.internal.verification.VerificationModeFactory.times; - -import java.io.File; -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.function.Consumer; -import org.apache.bookkeeper.bookie.BookieException; -import org.apache.bookkeeper.bookie.BookieImpl; -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.apache.bookkeeper.util.BookKeeperConstants; -import org.apache.bookkeeper.versioning.Version; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -/** - * Unit test for {@link AdminCommand}. - */ -@SuppressWarnings("unchecked") -public class AdminCommandTest extends BookieCommandTestBase { - - private static final BookieId bookieSocketAddress = BookieId.parse("localhost:9000"); - - private Versioned cookieVersioned; - private Cookie cookie; - - public AdminCommandTest() throws IOException { - super(3, 3); - } - - @Override - protected void mockServerConfigurationConstruction(Consumer consumer) { - Consumer compositeConsumer = (serverConfiguration) -> { - doReturn(bookieSocketAddress.getId()).when(serverConfiguration).getBookieId(); - if (consumer != null) { - consumer.accept(serverConfiguration); - } - }; - super.mockServerConfigurationConstruction(compositeConsumer); - } - - @Override - public void setup() throws Exception { - super.setup(); - - cookieVersioned = mock(Versioned.class); - cookie = mock(Cookie.class); - - mockStatic(Cookie.class); - mockStatic(BookieImpl.class); - - mockUpdateBookieIdInCookie(); - mockVerifyCookie(); - mockInitDirecotory(); - mockExpandStorage(); - mockListOrDeleteCookies(); - - } - - private void mockInitDirecotory() throws IOException { - File[] files = new File[1]; - files[0] = testDir.getRoot(); - testDir.newFile(BookKeeperConstants.VERSION_FILENAME); - getMockedStatic(BookieImpl.class).when(() -> BookieImpl.getCurrentDirectories(any())).thenReturn(files); - } - - private void mockUpdateBookieIdInCookie() throws Exception { - RegistrationManager registrationManager = mock(RegistrationManager.class); - - mockMetadataDriversWithRegistrationManager(registrationManager); - - getMockedStatic(Cookie.class).when(() -> Cookie - .readFromRegistrationManager(eq(registrationManager), any(ServerConfiguration.class))) - .thenReturn(cookieVersioned); - - getMockedStatic(Cookie.class).when(() -> Cookie - .readFromRegistrationManager(eq(registrationManager), eq(bookieSocketAddress))) - .thenReturn(cookieVersioned); - - when(cookieVersioned.getValue()).thenReturn(cookie); - Cookie.Builder builder = mock(Cookie.Builder.class); - getMockedStatic(Cookie.class).when(() -> Cookie.newBuilder(eq(cookie))).thenReturn(builder); - when(builder.setBookieId(anyString())).thenReturn(builder); - when(builder.build()).thenReturn(cookie); - - Version version = mock(Version.class); - when(cookieVersioned.getVersion()).thenReturn(version); - when(cookieVersioned.getValue()).thenReturn(cookie); - doNothing().when(cookie) - .deleteFromRegistrationManager( - eq(registrationManager), any(ServerConfiguration.class), eq(version)); - - doNothing().when(cookie).writeToDirectory(any(File.class)); - doNothing().when(cookie) - .writeToRegistrationManager( - eq(registrationManager), any(ServerConfiguration.class), eq(Version.NEW)); - - doNothing().when(cookie) - .deleteFromRegistrationManager( - eq(registrationManager), any(ServerConfiguration.class), eq(version)); - } - - private void mockVerifyCookie() throws IOException, BookieException.InvalidCookieException { - getMockedStatic(Cookie.class).when(() -> Cookie - .readFromDirectory(any(File.class))) - .thenReturn(cookie); - doNothing().when(cookie).verify(any(Cookie.class)); - } - - private void mockExpandStorage() throws Exception { - MetadataBookieDriver metadataBookieDriver = mock(MetadataBookieDriver.class); - RegistrationManager registrationManager = mock(RegistrationManager.class); - mockMetadataDriversWithMetadataBookieDriver(metadataBookieDriver); - when(metadataBookieDriver.createRegistrationManager()).thenReturn(registrationManager); - } - - private void mockListOrDeleteCookies() throws UnknownHostException { - getMockedStatic(BookieImpl.class).when(() -> BookieImpl.getBookieId(any(ServerConfiguration.class))) - .thenReturn(bookieSocketAddress); - } - - @Test - public void testWithoutAnyFlags() { - AdminCommand cmd = new AdminCommand(); - Assert.assertFalse(cmd.apply(bkFlags, new String[] {""})); - } - - @Test - public void testWithHostName() throws Exception { - mockServerConfigurationConstruction(serverConfiguration -> { - doReturn(true).when(serverConfiguration).getUseHostNameAsBookieID(); - }); - testCommand("-host"); - verify(cookie, times(2)).verify(any(Cookie.class)); - verify(getMockedConstruction(ServerConfiguration.class).constructed().get(1), - times(3)).setUseHostNameAsBookieID(anyBoolean()); - - } - - @Ignore - @Test - public void testWithExpand() { - testCommand("-e"); - } - - @Test - public void testWithList() { - testCommand("-l"); - } - - @Test - public void testWithDelete() throws BookieException { - testCommand("-d", "-f"); - verify(cookie, times(1)) - .deleteFromRegistrationManager(any(RegistrationManager.class), any(ServerConfiguration.class), - any(Version.class)); - } - - private void testCommand(String... args) { - AdminCommand cmd = new AdminCommand(); - Assert.assertTrue(cmd.apply(bkFlags, args)); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/CreateCookieCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/CreateCookieCommandTest.java deleted file mode 100644 index 5a785e89dda..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/CreateCookieCommandTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.commands.cookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import org.apache.bookkeeper.bookie.BookieException.CookieExistException; -import org.apache.bookkeeper.bookie.BookieException.OperationRejectedException; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.CookieCommandTestBase; -import org.apache.bookkeeper.tools.common.BKFlags; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test {@link CreateCookieCommand}. - */ -public class CreateCookieCommandTest extends CookieCommandTestBase { - - @Rule - public final TemporaryFolder testFolder = new TemporaryFolder(); - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - private final PrintStream console = new PrintStream(output); - - private boolean runCommand(String[] args) { - CreateCookieCommand createCmd = new CreateCookieCommand(console); - BKFlags bkFlags = new BKFlags(); - bkFlags.serviceUri = "zk://127.0.0.1"; - return createCmd.apply(bkFlags, args); - } - - private String getConsoleOutput() { - return new String(output.toByteArray(), UTF_8); - } - - /** - * Run a command without providing bookie id. - */ - @Test - public void testMissingBookieId() { - assertFalse(runCommand(new String[] {})); - String consoleOutput = getConsoleOutput(); - assertBookieIdMissing(consoleOutput); - } - - private void assertPrintUsage(String consoleOutput) { - assertPrintUsage(consoleOutput, "cookie_create [options]"); - } - - /** - * Run a command without cookie file. - */ - @Test - public void testMissingCookieFileOption() { - assertFalse(runCommand(new String[] { BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-cf | --cookie-file]"); - assertPrintUsage(consoleOutput); - } - - /** - * Run a command with invalid bookie id. - */ - @Test - public void testInvalidBookieId() { - assertFalse(runCommand(new String[] { "-cf", "test-cookie-file", INVALID_BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertInvalidBookieId(consoleOutput, INVALID_BOOKIE_ID); - } - - /** - * Run a command with a non-existent cookie file. - */ - @Test - public void testCreateCookieFromNonExistentCookieFile() { - String file = "/path/to/non-existent-cookie-file"; - assertFalse(runCommand(new String[] { "-cf", file, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertCookieFileNotExists(consoleOutput, file); - } - - /** - * A successful run. - */ - @SuppressWarnings("unchecked") - @Test - public void testCreateCookieFromExistentCookieFile() throws Exception { - File file = testFolder.newFile("test-cookie-file"); - byte[] content = "test-create-cookie".getBytes(UTF_8); - Files.write(Paths.get(file.toURI()), content); - String fileName = file.getPath(); - assertTrue(runCommand(new String[] { "-cf", fileName, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.isEmpty()); - verify(rm, times(1)).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - } - - /** - * Run a command to create cookie on an existing cookie. - */ - @SuppressWarnings("unchecked") - @Test - public void testCreateAlreadyExistedCookie() throws Exception { - doThrow(new CookieExistException()) - .when(rm).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - - File file = testFolder.newFile("test-cookie-file"); - byte[] content = "test-create-cookie".getBytes(UTF_8); - Files.write(Paths.get(file.toURI()), content); - String fileName = file.getPath(); - assertFalse(runCommand(new String[] { "-cf", fileName, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Cookie already exist for bookie '" + BOOKIE_ID + "'")); - verify(rm, times(1)).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - } - - /** - * Run a command to create cookie when exception is thrown. - */ - @SuppressWarnings("unchecked") - @Test - public void testCreateCookieException() throws Exception { - doThrow(new OperationRejectedException()) - .when(rm).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - - File file = testFolder.newFile("test-cookie-file"); - byte[] content = "test-create-cookie".getBytes(UTF_8); - Files.write(Paths.get(file.toURI()), content); - String fileName = file.getPath(); - assertFalse(runCommand(new String[] { "-cf", fileName, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Exception on creating cookie for bookie '" + BOOKIE_ID + "'")); - assertTrue( - consoleOutput, - consoleOutput.contains(OperationRejectedException.class.getName())); - verify(rm, times(1)).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/DeleteCookieCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/DeleteCookieCommandTest.java deleted file mode 100644 index c49f1eb28f9..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/DeleteCookieCommandTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.commands.cookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import org.apache.bookkeeper.bookie.BookieException.CookieNotFoundException; -import org.apache.bookkeeper.bookie.BookieException.OperationRejectedException; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.CookieCommandTestBase; -import org.apache.bookkeeper.tools.common.BKFlags; -import org.apache.bookkeeper.versioning.LongVersion; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test {@link DeleteCookieCommand}. - */ -public class DeleteCookieCommandTest extends CookieCommandTestBase { - - @Rule - public final TemporaryFolder testFolder = new TemporaryFolder(); - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - private final PrintStream console = new PrintStream(output); - - private boolean runCommand(String[] args) { - DeleteCookieCommand deleteCmd = new DeleteCookieCommand(console); - BKFlags bkFlags = new BKFlags(); - bkFlags.serviceUri = "zk://127.0.0.1"; - return deleteCmd.apply(bkFlags, args); - } - - private String getConsoleOutput() { - return new String(output.toByteArray(), UTF_8); - } - - /** - * Run a command without providing bookie id. - */ - @Test - public void testMissingBookieId() { - assertFalse(runCommand(new String[] {})); - String consoleOutput = getConsoleOutput(); - assertBookieIdMissing(consoleOutput); - } - - /** - * Run a command with invalid bookie id. - */ - @Test - public void testInvalidBookieId() { - assertFalse(runCommand(new String[] { INVALID_BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertInvalidBookieId(consoleOutput, INVALID_BOOKIE_ID); - } - - /** - * A successful run. - */ - @Test - public void testDeleteCookieFromExistentCookieFile() throws Exception { - assertTrue(runCommand(new String[] { BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.isEmpty()); - verify(rm, times(1)).removeCookie(eq(BookieId.parse(BOOKIE_ID)), eq(new LongVersion(-1L))); - } - - /** - * Run a command to delete cookie on an non-existent cookie. - */ - @Test - public void testDeleteNonExistedCookie() throws Exception { - doThrow(new CookieNotFoundException()) - .when(rm).removeCookie(eq(BookieId.parse(BOOKIE_ID)), eq(new LongVersion(-1L))); - - assertFalse(runCommand(new String[] { BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Cookie not found for bookie '" + BOOKIE_ID + "'")); - verify(rm, times(1)).removeCookie(eq(BookieId.parse(BOOKIE_ID)), eq(new LongVersion(-1L))); - } - - /** - * Run a command to delete cookie when exception is thrown. - */ - @Test - public void testDeleteCookieException() throws Exception { - doThrow(new OperationRejectedException()) - .when(rm).removeCookie(eq(BookieId.parse(BOOKIE_ID)), eq(new LongVersion(-1L))); - - assertFalse(runCommand(new String[] { BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Exception on deleting cookie for bookie '" + BOOKIE_ID + "'")); - assertTrue( - consoleOutput, - consoleOutput.contains(OperationRejectedException.class.getName())); - verify(rm, times(1)).removeCookie(eq(BookieId.parse(BOOKIE_ID)), eq(new LongVersion(-1L))); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandIndexTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandIndexTest.java deleted file mode 100644 index 7d3db61f3ea..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandIndexTest.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.commands.cookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.tools.cli.helpers.CookieCommandTestBase; -import org.apache.bookkeeper.tools.common.BKFlags; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test {@link GetCookieCommand}. - */ -public class GenerateCookieCommandIndexTest extends CookieCommandTestBase { - - @Rule - public final TemporaryFolder testFolder = new TemporaryFolder(); - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - private final PrintStream console = new PrintStream(output); - - private boolean runCommand(String[] args) { - GenerateCookieCommand getCmd = new GenerateCookieCommand(console); - BKFlags bkFlags = new BKFlags(); - bkFlags.serviceUri = "zk://127.0.0.1"; - return getCmd.apply(bkFlags, args); - } - - private String getConsoleOutput() { - return new String(output.toByteArray(), UTF_8); - } - - /** - * Run a command without providing bookie id. - */ - @Test - public void testMissingBookieId() { - assertFalse(runCommand(new String[] {})); - String consoleOutput = getConsoleOutput(); - assertBookieIdMissing(consoleOutput); - } - - /** - * Run a command with invalid bookie id. - */ - @Test - public void testInvalidBookieId() { - assertFalse(runCommand(new String[] { - "-j", "/path/to/journal", - "-l", "/path/to/ledgers", - "-o", "/path/to/cookie-file", - INVALID_BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertInvalidBookieId(consoleOutput, INVALID_BOOKIE_ID); - } - - /** - * Run a command without journal dirs. - */ - @Test - public void testMissingJournalDir() { - assertFalse(runCommand(new String[] { "-l", "/path/to/ledgers", "-o", "/path/to/cookie-file", BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-j | --journal-dirs]"); - } - - /** - * Run a command without ledger dirs. - */ - @Test - public void testMissingLedgerDirs() { - assertFalse(runCommand(new String[] { "-j", "/path/to/journal", "-o", "/path/to/cookie-file", BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-l | --ledger-dirs]"); - } - - /** - * Run a command without output file. - */ - @Test - public void testMissingOutputFile() { - assertFalse(runCommand(new String[] { "-j", "/path/to/journal", "-l", "/path/to/ledgers", BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-o | --output-file]"); - } - - /** - * A successful run without indexDir. - */ - @Test - public void testGenerateCookieWithoutIndexDir() throws Exception { - File cookieFile = testFolder.newFile("cookie-with-instance-id"); - String journalDir = "/path/to/journal"; - String ledgersDir = "/path/to/ledgers"; - String instanceId = "test-instance-id"; - - Cookie cookie = Cookie.newBuilder() - .setBookieId(BOOKIE_ID) - .setInstanceId(instanceId) - .setJournalDirs(journalDir) - .setLedgerDirs(Cookie.encodeDirPaths(ledgersDir.split(","))) - .build(); - - when(rm.getClusterInstanceId()).thenReturn(instanceId); - assertTrue( - getConsoleOutput(), - runCommand(new String[] { - "-l", ledgersDir, - "-j", journalDir, - "-o", cookieFile.getPath(), - "-i", instanceId, - BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains( - "Successfully saved the generated cookie to " + cookieFile.getPath() - )); - verify(rm, times(0)).getClusterInstanceId(); - - byte[] data = Files.readAllBytes(Paths.get(cookieFile.getPath())); - assertEquals(cookie.toString(), new String(data, UTF_8)); - } - - /** - * A successful run without instance id. - */ - @Test - public void testGenerateCookieWithoutInstanceId() throws Exception { - File cookieFile = testFolder.newFile("cookie-without-instance-id"); - String journalDir = "/path/to/journal"; - String ledgersDir = "/path/to/ledgers"; - String indexDir = "/path/to/indexs"; - String instanceId = "test-instance-id"; - - Cookie cookie = Cookie.newBuilder() - .setBookieId(BOOKIE_ID) - .setInstanceId(instanceId) - .setJournalDirs(journalDir) - .setLedgerDirs(Cookie.encodeDirPaths(ledgersDir.split(","))) - .setIndexDirs(Cookie.encodeDirPaths(indexDir.split(","))) - .build(); - - when(rm.getClusterInstanceId()).thenReturn(instanceId); - assertTrue( - getConsoleOutput(), - runCommand(new String[] { - "-l", ledgersDir, - "-j", journalDir, - "-ix", indexDir, - "-o", cookieFile.getPath(), - BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains( - "Successfully saved the generated cookie to " + cookieFile.getPath() - )); - verify(rm, times(1)).getClusterInstanceId(); - - byte[] data = Files.readAllBytes(Paths.get(cookieFile.getPath())); - assertArrayEquals(cookie.toString().getBytes(UTF_8), data); - } - - /** - * A successful run with instance id. - */ - @Test - public void testGenerateCookieWithInstanceId() throws Exception { - File cookieFile = testFolder.newFile("cookie-with-instance-id"); - String journalDir = "/path/to/journal"; - String ledgersDir = "/path/to/ledgers"; - String indexsDir = "/path/to/indexs"; - String instanceId = "test-instance-id"; - - Cookie cookie = Cookie.newBuilder() - .setBookieId(BOOKIE_ID) - .setInstanceId(instanceId) - .setJournalDirs(journalDir) - .setLedgerDirs(Cookie.encodeDirPaths(ledgersDir.split(","))) - .setIndexDirs(Cookie.encodeDirPaths(indexsDir.split(","))) - .build(); - - when(rm.getClusterInstanceId()).thenReturn(instanceId); - assertTrue( - getConsoleOutput(), - runCommand(new String[] { - "-l", ledgersDir, - "-ix", indexsDir, - "-j", journalDir, - "-o", cookieFile.getPath(), - "-i", instanceId, - BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains( - "Successfully saved the generated cookie to " + cookieFile.getPath() - )); - verify(rm, times(0)).getClusterInstanceId(); - - byte[] data = Files.readAllBytes(Paths.get(cookieFile.getPath())); - assertArrayEquals(cookie.toString().getBytes(UTF_8), data); - } - - /** - * A successful run with encoding multiple ledgers while generating cookie. - */ - @Test - public void testGenerateCookieWithMultipleLedgerIndexDirs() throws Exception { - File cookieFile = testFolder.newFile("cookie-with-instance-id"); - String journalDir = "/path/to/journal"; - String ledgerDirs = "/path/to/ledgers,/path/to/more/ledgers"; - String indexDirs = "/path/to/indexs,/path/to/more/indexs"; - String instanceId = "test-instance-id"; - - when(rm.getClusterInstanceId()).thenReturn(instanceId); - assertTrue( - getConsoleOutput(), - runCommand(new String[] { - "-l", ledgerDirs, - "-ix", indexDirs, - "-j", journalDir, - "-o", cookieFile.getPath(), - "-i", instanceId, - BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains( - "Successfully saved the generated cookie to " + cookieFile.getPath() - )); - verify(rm, times(0)).getClusterInstanceId(); - - List cookieFields = Files.readAllLines(Paths.get(cookieFile.getPath())); - for (String cookieField : cookieFields) { - String[] fields = cookieField.split(" "); - if (fields[0].equals("ledgerDirs:")) { - assertEquals(fields[1], "\"" + encodeDirPaths(ledgerDirs.split(",")) + "\""); - } - if (fields[0].equals("indexDirs:")) { - assertEquals(fields[1], "\"" + encodeDirPaths(indexDirs.split(",")) + "\""); - } - } - } - - public String encodeDirPaths(String[] dirs) { - StringBuilder b = new StringBuilder(); - b.append(dirs.length); - for (String d : dirs) { - b.append("\\t").append(d); - } - return b.toString(); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandTest.java deleted file mode 100644 index 1fb4b32feb2..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GenerateCookieCommandTest.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.commands.cookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.tools.cli.helpers.CookieCommandTestBase; -import org.apache.bookkeeper.tools.common.BKFlags; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test {@link GetCookieCommand}. - */ -public class GenerateCookieCommandTest extends CookieCommandTestBase { - - @Rule - public final TemporaryFolder testFolder = new TemporaryFolder(); - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - private final PrintStream console = new PrintStream(output); - - private boolean runCommand(String[] args) { - GenerateCookieCommand getCmd = new GenerateCookieCommand(console); - BKFlags bkFlags = new BKFlags(); - bkFlags.serviceUri = "zk://127.0.0.1"; - return getCmd.apply(bkFlags, args); - } - - private String getConsoleOutput() { - return new String(output.toByteArray(), UTF_8); - } - - /** - * Run a command without providing bookie id. - */ - @Test - public void testMissingBookieId() { - assertFalse(runCommand(new String[] {})); - String consoleOutput = getConsoleOutput(); - assertBookieIdMissing(consoleOutput); - } - - /** - * Run a command with invalid bookie id. - */ - @Test - public void testInvalidBookieId() { - assertFalse(runCommand(new String[] { - "-j", "/path/to/journal", - "-l", "/path/to/ledgers", - "-o", "/path/to/cookie-file", - INVALID_BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertInvalidBookieId(consoleOutput, INVALID_BOOKIE_ID); - } - - /** - * Run a command without journal dirs. - */ - @Test - public void testMissingJournalDir() { - assertFalse(runCommand(new String[] { "-l", "/path/to/ledgers", "-o", "/path/to/cookie-file", BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-j | --journal-dirs]"); - } - - /** - * Run a command without ledger dirs. - */ - @Test - public void testMissingLedgerDirs() { - assertFalse(runCommand(new String[] { "-j", "/path/to/journal", "-o", "/path/to/cookie-file", BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-l | --ledger-dirs]"); - } - - /** - * Run a command without output file. - */ - @Test - public void testMissingOutputFile() { - assertFalse(runCommand(new String[] { "-j", "/path/to/journal", "-l", "/path/to/ledgers", BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-o | --output-file]"); - } - - /** - * A successful run without instance id. - */ - @Test - public void testGenerateCookieWithoutInstanceId() throws Exception { - File cookieFile = testFolder.newFile("cookie-without-instance-id"); - String journalDir = "/path/to/journal"; - String ledgersDir = "/path/to/ledgers"; - String instanceId = "test-instance-id"; - - Cookie cookie = Cookie.newBuilder() - .setBookieId(BOOKIE_ID) - .setInstanceId(instanceId) - .setJournalDirs(journalDir) - .setLedgerDirs(Cookie.encodeDirPaths(ledgersDir.split(","))) - .build(); - - when(rm.getClusterInstanceId()).thenReturn(instanceId); - assertTrue( - getConsoleOutput(), - runCommand(new String[] { - "-l", ledgersDir, - "-j", journalDir, - "-o", cookieFile.getPath(), - BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains( - "Successfully saved the generated cookie to " + cookieFile.getPath() - )); - verify(rm, times(1)).getClusterInstanceId(); - - byte[] data = Files.readAllBytes(Paths.get(cookieFile.getPath())); - assertArrayEquals(cookie.toString().getBytes(UTF_8), data); - } - - /** - * A successful run with instance id. - */ - @Test - public void testGenerateCookieWithInstanceId() throws Exception { - File cookieFile = testFolder.newFile("cookie-with-instance-id"); - String journalDir = "/path/to/journal"; - String ledgersDir = "/path/to/ledgers"; - String instanceId = "test-instance-id"; - - Cookie cookie = Cookie.newBuilder() - .setBookieId(BOOKIE_ID) - .setInstanceId(instanceId) - .setJournalDirs(journalDir) - .setLedgerDirs(Cookie.encodeDirPaths(ledgersDir.split(","))) - .build(); - - when(rm.getClusterInstanceId()).thenReturn(instanceId); - assertTrue( - getConsoleOutput(), - runCommand(new String[] { - "-l", ledgersDir, - "-j", journalDir, - "-o", cookieFile.getPath(), - "-i", instanceId, - BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains( - "Successfully saved the generated cookie to " + cookieFile.getPath() - )); - verify(rm, times(0)).getClusterInstanceId(); - - byte[] data = Files.readAllBytes(Paths.get(cookieFile.getPath())); - assertArrayEquals(cookie.toString().getBytes(UTF_8), data); - } - - /** - * A successful run with encoding multiple ledgers while generating cookie. - */ - @Test - public void testGenerateCookieWithMultipleLedgerDirs() throws Exception { - File cookieFile = testFolder.newFile("cookie-with-instance-id"); - String journalDir = "/path/to/journal"; - String ledgersDir = "/path/to/ledgers,/path/to/more/ledgers"; - String instanceId = "test-instance-id"; - - when(rm.getClusterInstanceId()).thenReturn(instanceId); - assertTrue( - getConsoleOutput(), - runCommand(new String[] { - "-l", ledgersDir, - "-j", journalDir, - "-o", cookieFile.getPath(), - "-i", instanceId, - BOOKIE_ID - })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains( - "Successfully saved the generated cookie to " + cookieFile.getPath() - )); - verify(rm, times(0)).getClusterInstanceId(); - - List cookieFields = Files.readAllLines(Paths.get(cookieFile.getPath())); - for (String cookieField : cookieFields) { - String[] fields = cookieField.split(" "); - if (fields[0].equals("ledgerDirs:")) { - assertEquals(fields[1].charAt(1), '2'); - } - } - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GetCookieCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GetCookieCommandTest.java deleted file mode 100644 index d91f49ebbc1..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/GetCookieCommandTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.commands.cookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import org.apache.bookkeeper.bookie.BookieException.CookieNotFoundException; -import org.apache.bookkeeper.bookie.BookieException.OperationRejectedException; -import org.apache.bookkeeper.bookie.Cookie; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.CookieCommandTestBase; -import org.apache.bookkeeper.tools.common.BKFlags; -import org.apache.bookkeeper.versioning.LongVersion; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test {@link GetCookieCommand}. - */ -public class GetCookieCommandTest extends CookieCommandTestBase { - - @Rule - public final TemporaryFolder testFolder = new TemporaryFolder(); - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - private final PrintStream console = new PrintStream(output); - - private boolean runCommand(String[] args) { - GetCookieCommand getCmd = new GetCookieCommand(console); - BKFlags bkFlags = new BKFlags(); - bkFlags.serviceUri = "zk://127.0.0.1"; - return getCmd.apply(bkFlags, args); - } - - private String getConsoleOutput() { - return new String(output.toByteArray(), UTF_8); - } - - /** - * Run a command without providing bookie id. - */ - @Test - public void testMissingBookieId() { - assertFalse(runCommand(new String[] {})); - String consoleOutput = getConsoleOutput(); - assertBookieIdMissing(consoleOutput); - } - - /** - * Run a command with invalid bookie id. - */ - @Test - public void testInvalidBookieId() { - assertFalse(runCommand(new String[] { INVALID_BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertInvalidBookieId(consoleOutput, INVALID_BOOKIE_ID); - } - - /** - * A successful run. - */ - @Test - public void testGetCookieFromExistentCookieFile() throws Exception { - Cookie cookie = Cookie.newBuilder() - .setBookieId(BOOKIE_ID) - .setInstanceId("test-instance-id") - .setJournalDirs("/path/to/journal/dir") - .setLedgerDirs("/path/to/ledger/dirs") - .build(); - when(rm.readCookie(eq(BookieId.parse(BOOKIE_ID)))) - .thenReturn(new Versioned<>(cookie.toString().getBytes(UTF_8), new LongVersion(-1L))); - assertTrue(runCommand(new String[] {BOOKIE_ID})); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.contains(cookie.toString())); - verify(rm, times(1)).readCookie(eq(BookieId.parse(BOOKIE_ID))); - } - - /** - * Run a command to get cookie on an non-existent cookie. - */ - @Test - public void testGetNonExistedCookie() throws Exception { - doThrow(new CookieNotFoundException()) - .when(rm).readCookie(eq(BookieId.parse(BOOKIE_ID))); - - assertFalse(runCommand(new String[] { BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Cookie not found for bookie '" + BOOKIE_ID + "'")); - verify(rm, times(1)).readCookie(eq(BookieId.parse(BOOKIE_ID))); - } - - /** - * Run a command to get cookie when exception is thrown. - */ - @Test - public void testGetCookieException() throws Exception { - doThrow(new OperationRejectedException()) - .when(rm).readCookie(eq(BookieId.parse(BOOKIE_ID))); - - assertFalse(runCommand(new String[] { BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Exception on getting cookie for bookie '" + BOOKIE_ID + "'")); - assertTrue( - consoleOutput, - consoleOutput.contains(OperationRejectedException.class.getName())); - verify(rm, times(1)).readCookie(eq(BookieId.parse(BOOKIE_ID))); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/UpdateCookieCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/UpdateCookieCommandTest.java deleted file mode 100644 index 7ee8c844405..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/UpdateCookieCommandTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.commands.cookie; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import org.apache.bookkeeper.bookie.BookieException.CookieNotFoundException; -import org.apache.bookkeeper.bookie.BookieException.OperationRejectedException; -import org.apache.bookkeeper.net.BookieId; -import org.apache.bookkeeper.tools.cli.helpers.CookieCommandTestBase; -import org.apache.bookkeeper.tools.common.BKFlags; -import org.apache.bookkeeper.versioning.Versioned; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Unit test {@link UpdateCookieCommand}. - */ -public class UpdateCookieCommandTest extends CookieCommandTestBase { - - @Rule - public final TemporaryFolder testFolder = new TemporaryFolder(); - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - private final PrintStream console = new PrintStream(output); - - private boolean runCommand(String[] args) { - UpdateCookieCommand updateCmd = new UpdateCookieCommand(console); - BKFlags bkFlags = new BKFlags(); - bkFlags.serviceUri = "zk://127.0.0.1"; - return updateCmd.apply(bkFlags, args); - } - - private String getConsoleOutput() { - return new String(output.toByteArray(), UTF_8); - } - - /** - * Run a command without providing bookie id. - */ - @Test - public void testMissingBookieId() { - assertFalse(runCommand(new String[] {})); - String consoleOutput = getConsoleOutput(); - assertBookieIdMissing(consoleOutput); - } - - private void assertPrintUsage(String consoleOutput) { - assertPrintUsage(consoleOutput, "cookie_update [options]"); - } - - /** - * Run a command without cookie file. - */ - @Test - public void testMissingCookieFileOption() { - assertFalse(runCommand(new String[] { BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertOptionMissing(consoleOutput, "[-cf | --cookie-file]"); - assertPrintUsage(consoleOutput); - } - - /** - * Run a command with invalid bookie id. - */ - @Test - public void testInvalidBookieId() { - assertFalse(runCommand(new String[] { "-cf", "test-cookie-file", INVALID_BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertInvalidBookieId(consoleOutput, INVALID_BOOKIE_ID); - } - - /** - * Run a command with a non-existent cookie file. - */ - @Test - public void testUpdateCookieFromNonExistentCookieFile() { - String file = "/path/to/non-existent-cookie-file"; - assertFalse(runCommand(new String[] { "-cf", file, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertCookieFileNotExists(consoleOutput, file); - } - - /** - * A successful run. - */ - @SuppressWarnings("unchecked") - @Test - public void testUpdateCookieFromExistentCookieFile() throws Exception { - File file = testFolder.newFile("test-cookie-file"); - byte[] content = "test-update-cookie".getBytes(UTF_8); - Files.write(Paths.get(file.toURI()), content); - String fileName = file.getPath(); - assertTrue(runCommand(new String[] { "-cf", fileName, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue(consoleOutput, consoleOutput.isEmpty()); - verify(rm, times(1)).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - } - - /** - * Run a command to update cookie on an non-existent cookie. - */ - @SuppressWarnings("unchecked") - @Test - public void testUpdateNonExistedCookie() throws Exception { - doThrow(new CookieNotFoundException()) - .when(rm).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - - File file = testFolder.newFile("test-cookie-file"); - byte[] content = "test-update-cookie".getBytes(UTF_8); - Files.write(Paths.get(file.toURI()), content); - String fileName = file.getPath(); - assertFalse(runCommand(new String[] { "-cf", fileName, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Cookie not found for bookie '" + BOOKIE_ID + "'")); - verify(rm, times(1)).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - } - - /** - * Run a command to update cookie when exception is thrown. - */ - @SuppressWarnings("unchecked") - @Test - public void testUpdateCookieException() throws Exception { - doThrow(new OperationRejectedException()) - .when(rm).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - - File file = testFolder.newFile("test-cookie-file"); - byte[] content = "test-update-cookie".getBytes(UTF_8); - Files.write(Paths.get(file.toURI()), content); - String fileName = file.getPath(); - assertFalse(runCommand(new String[] { "-cf", fileName, BOOKIE_ID })); - String consoleOutput = getConsoleOutput(); - assertTrue( - consoleOutput, - consoleOutput.contains("Exception on updating cookie for bookie '" + BOOKIE_ID + "'")); - assertTrue( - consoleOutput, - consoleOutput.contains(OperationRejectedException.class.getName())); - verify(rm, times(1)).writeCookie(eq(BookieId.parse(BOOKIE_ID)), any(Versioned.class)); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/health/SwitchOfHealthCheckCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/health/SwitchOfHealthCheckCommandTest.java deleted file mode 100644 index a715fbf4e17..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/health/SwitchOfHealthCheckCommandTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.commands.health; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.common.concurrent.FutureUtils; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataClientDriver; -import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; -import org.junit.Assert; -import org.junit.Test; - - -/** - * Unit test for {@link SwitchOfHealthCheckCommand}. - */ -public class SwitchOfHealthCheckCommandTest extends BookieCommandTestBase { - MetadataClientDriver metadataClientDriver; - private MetadataBookieDriver metadataBookieDriver; - - - public SwitchOfHealthCheckCommandTest() { - super(3, 0); - } - - @Override - public void setup() throws Exception { - super.setup(); - mockServerConfigurationConstruction(); - metadataBookieDriver = mock(MetadataBookieDriver.class); - mockMetadataDriversWithMetadataBookieDriver(metadataBookieDriver); - metadataClientDriver = mock(MetadataClientDriver.class); - when(metadataBookieDriver.isHealthCheckEnabled()).thenReturn(FutureUtils.value(true)); - when(metadataBookieDriver.disableHealthCheck()).thenReturn(FutureUtils.value(null)); - } - - @Test - public void testWithEnable() { - testCommand("-e"); - } - - @Test - public void testWithStatus() { - testCommand("-s"); - } - - - @Test - public void testWithNoArgsDisable() { - testCommand(""); - } - - private void testCommand(String... args) { - SwitchOfHealthCheckCommand cmd = new SwitchOfHealthCheckCommand(); - Assert.assertTrue(cmd.apply(bkFlags, args)); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieCommandTestBase.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieCommandTestBase.java deleted file mode 100644 index 739b1b2d839..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieCommandTestBase.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.helpers; - -import java.io.File; -import org.junit.Before; - -/** - * A test base for testing bookie commands. - */ -public abstract class BookieCommandTestBase extends CommandTestBase { - - protected final int numJournalDirs; - protected final int numLedgerDirs; - - protected BookieCommandTestBase(int numJournalDirs, int numLedgerDirs) { - this.numJournalDirs = numJournalDirs; - this.numLedgerDirs = numLedgerDirs; - } - - @Before - public void setup() throws Exception { - String[] journalDirs = new String[numJournalDirs]; - for (int i = 0; i < numJournalDirs; i++) { - File dir = testDir.newFile(); - dir.mkdirs(); - journalDirs[i] = dir.getAbsolutePath(); - } - journalDirsName = journalDirs; - String[] ledgerDirs = new String[numLedgerDirs]; - for (int i = 0; i < numLedgerDirs; i++) { - File dir = testDir.newFile(); - dir.mkdirs(); - ledgerDirs[i] = dir.getAbsolutePath(); - } - ledgerDirNames = ledgerDirs; - - String[] indexDirs = new String[numLedgerDirs]; - for (int i = 0; i < numLedgerDirs; i++) { - File dir = testDir.newFile(); - dir.mkdirs(); - indexDirs[i] = dir.getAbsolutePath(); - } - indexDirNames = indexDirs; - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieShellCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieShellCommandTest.java deleted file mode 100644 index 9597cdeef21..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/BookieShellCommandTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.apache.bookkeeper.tools.common.BKCommand; -import org.apache.bookkeeper.tools.framework.CliFlags; -import org.apache.commons.configuration.CompositeConfiguration; -import org.junit.Test; - -/** - * Unit test {@link BookieShellCommand}. - */ -public class BookieShellCommandTest { - - @SuppressWarnings("unchecked") - @Test - public void testShellCommand() throws Exception { - BKCommand command = mock(BKCommand.class); - String shellCommandName = "test-shell-command"; - CompositeConfiguration conf = new CompositeConfiguration(); - BookieShellCommand shellCommand = new BookieShellCommand<>( - shellCommandName, - command, - conf); - - // test `description` - assertEquals( - shellCommandName + " [options]", - shellCommand.description()); - - // test `printUsage` - shellCommand.printUsage(); - verify(command, times(1)).usage(); - - // test `runCmd` - String[] args = new String[] { "arg-1", "arg-2" }; - shellCommand.runCmd(args); - verify(command, times(1)) - .apply(same(shellCommandName), same(conf), same(args)); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTest.java deleted file mode 100644 index ead1ee5d38e..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.bookkeeper.client.api.BookKeeper; -import org.apache.bookkeeper.client.api.BookKeeperBuilder; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.tools.framework.CliFlags; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test of {@link ClientCommand}. - */ -public class ClientCommandTest extends MockCommandSupport { - - private ClientCommand cmd; - private ServerConfiguration serverConf; - private ClientConfiguration clientConf; - private BookKeeperBuilder bkBuilder; - private BookKeeper bk; - - @SuppressWarnings("unchecked") - @Before - public void setup() throws Exception { - this.cmd = mock(ClientCommand.class, CALLS_REAL_METHODS); - this.serverConf = new ServerConfiguration(); - this.serverConf.setMetadataServiceUri("zk://127.0.0.1/path/to/ledgers"); - mockConstruction(ClientConfiguration.class, (conf, context) -> { - doReturn("zk://127.0.0.1/path/to/ledgers").when(conf).getMetadataServiceUri(); - doReturn(true).when(conf).getBookieAddressResolverEnabled(); - }); - this.bkBuilder = mock(BookKeeperBuilder.class, CALLS_REAL_METHODS); - mockStatic(BookKeeper.class).when(() -> - BookKeeper.newBuilder(any(ClientConfiguration.class))).thenReturn(bkBuilder); - this.bk = mock(BookKeeper.class); - when(bkBuilder.build()).thenReturn(bk); - } - - @Test - public void testRun() throws Exception { - CliFlags flags = new CliFlags(); - assertTrue(cmd.apply(serverConf, flags)); - verify(cmd, times(1)).run(eq(bk), same(flags)); - verify(bkBuilder, times(1)).build(); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTestBase.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTestBase.java deleted file mode 100644 index 158a740cf81..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/ClientCommandTestBase.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.mockito.Answers.CALLS_REAL_METHODS; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.withSettings; - -import java.net.URI; -import org.apache.bookkeeper.client.api.BookKeeper; -import org.apache.bookkeeper.client.api.BookKeeperBuilder; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.meta.MetadataClientDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.junit.Before; - -/** - * A test base for testing client commands. - */ -public abstract class ClientCommandTestBase extends CommandTestBase { - - protected BookKeeperBuilder mockBkBuilder; - protected BookKeeper mockBk; - protected MetadataClientDriver metadataClientDriver; - - @Before - public void setup() throws Exception { - mockBk = mock(BookKeeper.class); - mockConstruction(ClientConfiguration.class, withSettings().defaultAnswer(CALLS_REAL_METHODS), - (mock, context) -> { - doReturn("zk://127.0.0.1/path/to/ledgers").when(mock).getMetadataServiceUri(); - doReturn(true).when(mock).getBookieAddressResolverEnabled(); - }); - - mockStatic(BookKeeper.class); - this.mockBkBuilder = mock(BookKeeperBuilder.class, CALLS_REAL_METHODS); - this.mockBk = mock(BookKeeper.class); - getMockedStatic(BookKeeper.class).when(() -> BookKeeper.newBuilder(any(ClientConfiguration.class))) - .thenReturn(mockBkBuilder); - when(mockBkBuilder.build()).thenReturn(mockBk); - - this.metadataClientDriver = mock(MetadataClientDriver.class); - mockStatic(MetadataDrivers.class); - getMockedStatic(MetadataDrivers.class).when(() -> MetadataDrivers.getClientDriver(any(URI.class))) - .thenReturn(metadataClientDriver); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CommandTestBase.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CommandTestBase.java deleted file mode 100644 index 2e774d45187..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CommandTestBase.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doCallRealMethod; -import static org.mockito.Mockito.doReturn; - -import java.util.function.Consumer; -import java.util.function.Function; -import lombok.extern.slf4j.Slf4j; -import org.apache.bookkeeper.client.BookKeeperAdmin; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.conf.ServerConfiguration; -import org.apache.bookkeeper.discover.RegistrationManager; -import org.apache.bookkeeper.meta.LedgerManagerFactory; -import org.apache.bookkeeper.meta.MetadataBookieDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.tools.common.BKFlags; -import org.junit.Rule; -import org.junit.rules.TemporaryFolder; -import org.mockito.MockedStatic; - - - -/** - * A test base providing an environment for run a command. - */ -@Slf4j -@SuppressWarnings("unchecked") -public class CommandTestBase extends MockCommandSupport { - - @Rule - public final TemporaryFolder testDir = new TemporaryFolder(); - protected String[] journalDirsName; - protected String[] ledgerDirNames; - protected String[] indexDirNames; - - protected final BKFlags bkFlags; - protected MockedStatic mockMetadataDrivers() { - if (unsafeGetMockedStatic(MetadataDrivers.class) == null) { - mockStatic(MetadataDrivers.class); - } - return getMockedStatic(MetadataDrivers.class); - } - - protected void mockMetadataDriversWithRegistrationManager(RegistrationManager registrationManager) { - mockMetadataDrivers().when(() -> MetadataDrivers - .runFunctionWithRegistrationManager(any(ServerConfiguration.class), any(Function.class)) - ).then(invocation -> { - Function func = invocation.getArgument(1); - func.apply(registrationManager); - return true; - }); - } - - protected void mockMetadataDriversWithMetadataBookieDriver(MetadataBookieDriver metadataBookieDriver) { - mockMetadataDrivers().when(() -> MetadataDrivers - .runFunctionWithMetadataBookieDriver(any(ServerConfiguration.class), any(Function.class)) - ).then(invocation -> { - Function func = invocation.getArgument(1); - func.apply(metadataBookieDriver); - return true; - }); - } - - protected void mockMetadataDriversWithLedgerManagerFactory(LedgerManagerFactory ledgerManagerFactory) { - mockMetadataDrivers().when(() -> MetadataDrivers - .runFunctionWithLedgerManagerFactory(any(ServerConfiguration.class), any(Function.class)) - ).then(invocation -> { - Function func = invocation.getArgument(1); - func.apply(ledgerManagerFactory); - return true; - }); - } - - protected void mockServerConfigurationConstruction() { - mockServerConfigurationConstruction(null); - } - - protected void mockServerConfigurationConstruction(Consumer consumer) { - mockConstruction(ServerConfiguration.class, (serverConfiguration, context) -> { - final ServerConfiguration defaultConf = new ServerConfiguration(); - doReturn("zk://127.0.0.1/path/to/ledgers").when(serverConfiguration).getMetadataServiceUri(); - if (journalDirsName != null) { - doReturn(journalDirsName).when(serverConfiguration).getJournalDirNames(); - doCallRealMethod().when(serverConfiguration).getJournalDirs(); - } - if (ledgerDirNames != null) { - doReturn(ledgerDirNames).when(serverConfiguration).getLedgerDirNames(); - doCallRealMethod().when(serverConfiguration).getLedgerDirs(); - } - if (indexDirNames != null) { - doReturn(indexDirNames).when(serverConfiguration).getIndexDirNames(); - doCallRealMethod().when(serverConfiguration).getIndexDirs(); - } - doReturn(defaultConf.getDiskUsageThreshold()).when(serverConfiguration).getDiskUsageThreshold(); - doReturn(defaultConf.getDiskUsageWarnThreshold()).when(serverConfiguration).getDiskUsageWarnThreshold(); - if (consumer != null) { - consumer.accept(serverConfiguration); - } - }); - } - - protected void mockClientConfigurationConstruction() { - mockClientConfigurationConstruction(null); - } - - protected void mockClientConfigurationConstruction(Consumer consumer) { - mockConstruction(ClientConfiguration.class, (clientConfiguration, context) -> { - doReturn("zk://127.0.0.1/path/to/ledgers").when(clientConfiguration).getMetadataServiceUri(); - doReturn(true).when(clientConfiguration).getBookieAddressResolverEnabled(); - if (consumer != null) { - consumer.accept(clientConfiguration); - } - }); - } - - protected void mockBookKeeperAdminConstruction() { - mockBookKeeperAdminConstruction(null); - } - - protected void mockBookKeeperAdminConstruction(Consumer consumer) { - mockConstruction(BookKeeperAdmin.class, (bookKeeperAdmin, context) -> { - if (consumer != null) { - consumer.accept(bookKeeperAdmin); - } - }); - } - - public CommandTestBase() { - this.bkFlags = new BKFlags(); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CookieCommandTestBase.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CookieCommandTestBase.java deleted file mode 100644 index 3a9a155217b..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/CookieCommandTestBase.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ - -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import org.apache.bookkeeper.discover.RegistrationManager; -import org.junit.Before; - -/** - * A test base for testing cookie commands. - */ -public class CookieCommandTestBase extends CommandTestBase { - - protected static final String INVALID_BOOKIE_ID = "127.0.0.1"; - protected static final String BOOKIE_ID = "127.0.0.1:3181"; - - protected RegistrationManager rm; - - - @Before - public void setup() throws Exception { - this.rm = mock(RegistrationManager.class); - mockMetadataDriversWithRegistrationManager(rm); - } - - protected void assertBookieIdMissing(String consoleOutput) { - assertTrue( - consoleOutput, - consoleOutput.contains("No bookie id or more bookie ids is specified") - ); - } - - protected void assertInvalidBookieId(String consoleOutput, String bookieId) { - assertTrue( - consoleOutput, - consoleOutput.contains("Invalid bookie id '" + bookieId + "'")); - } - - protected void assertOptionMissing(String consoleOutput, String option) { - assertTrue( - consoleOutput, - consoleOutput.contains("The following option is required: " + option)); - } - - protected void assertPrintUsage(String consoleOutput, String usage) { - assertTrue( - consoleOutput, - consoleOutput.contains("Usage: " + usage)); - } - - protected void assertCookieFileNotExists(String consoleOutput, String cookieFile) { - assertTrue( - consoleOutput, - consoleOutput.contains("Cookie file '" + cookieFile + "' doesn't exist.")); - } - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTest.java deleted file mode 100644 index c4c9f8d9f50..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Answers.CALLS_REAL_METHODS; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.net.URI; -import java.util.Optional; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.bookkeeper.conf.ClientConfiguration; -import org.apache.bookkeeper.discover.RegistrationClient; -import org.apache.bookkeeper.meta.MetadataClientDriver; -import org.apache.bookkeeper.meta.MetadataDrivers; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.tools.framework.CliFlags; -import org.junit.Before; -import org.junit.experimental.theories.DataPoint; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -/** - * Unit test of {@link DiscoveryCommand}. - */ -@RunWith(Theories.class) -public class DiscoveryCommandTest { - - private DiscoveryCommand cmd; - private ClientConfiguration clientConf; - private RegistrationClient regClient; - private MetadataClientDriver clientDriver; - private ScheduledExecutorService executor; - - @SuppressWarnings("unchecked") - @Before - public void setup() throws Exception { - - this.cmd = mock(DiscoveryCommand.class, CALLS_REAL_METHODS); - - this.clientConf = new ClientConfiguration(); - this.clientConf.setMetadataServiceUri("zk://127.0.0.1/path/to/ledgers"); - this.executor = mock(ScheduledExecutorService.class); - this.regClient = mock(RegistrationClient.class); - this.clientDriver = mock(MetadataClientDriver.class); - when(clientDriver.getRegistrationClient()) - .thenReturn(regClient); - } - - @DataPoint - public static final boolean BOOKIE_ADDR_RESOLVER_ENABLED = true; - @DataPoint - public static final boolean BOOKIE_ADDR_RESOLVER_DISABLED = false; - @Theory - public void testRun(boolean bookieAddressResolverEnabled) throws Exception { - clientConf.setBookieAddressResolverEnabled(bookieAddressResolverEnabled); - - try (final MockedStatic executorsMockedStatic = Mockito.mockStatic(Executors.class); - final MockedStatic mdriversMockedStatic = Mockito.mockStatic(MetadataDrivers.class);) { - executorsMockedStatic - .when(() -> Executors.newSingleThreadScheduledExecutor()).thenReturn(executor); - mdriversMockedStatic.when(() -> MetadataDrivers.getClientDriver(any(URI.class))) - .thenReturn(clientDriver); - - CliFlags cliFlags = new CliFlags(); - assertTrue(cmd.apply(clientConf, cliFlags)); - verify(cmd, times(1)).run(eq(regClient), same(cliFlags), eq(bookieAddressResolverEnabled)); - verify(clientDriver, times(1)) - .initialize( - any(ClientConfiguration.class), eq(executor), - eq(NullStatsLogger.INSTANCE), eq(Optional.empty())); - verify(clientDriver, times(1)).getRegistrationClient(); - verify(clientDriver, times(1)).close(); - verify(executor, times(1)).shutdown(); - } - } - - -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTestBase.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTestBase.java deleted file mode 100644 index 15a34fd39b1..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/DiscoveryCommandTestBase.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.bookkeeper.discover.RegistrationClient; -import org.junit.Before; -/** - * A test base for discovery related commands. - */ -public abstract class DiscoveryCommandTestBase extends ClientCommandTestBase { - - protected RegistrationClient regClient; - protected ScheduledExecutorService executor; - - @Before - public void setup() throws Exception { - super.setup(); - - this.executor = mock(ScheduledExecutorService.class); - mockStatic(Executors.class).when(() -> Executors.newSingleThreadScheduledExecutor()).thenReturn(executor); - this.regClient = mock(RegistrationClient.class); - when(metadataClientDriver.getRegistrationClient()) - .thenReturn(regClient); - } -} diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/MockCommandSupport.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/MockCommandSupport.java deleted file mode 100644 index 22acb0de727..00000000000 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/helpers/MockCommandSupport.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF 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. - */ -package org.apache.bookkeeper.tools.cli.helpers; - -import static org.mockito.Mockito.withSettings; - -import java.util.HashMap; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import org.junit.After; -import org.mockito.MockSettings; -import org.mockito.MockedConstruction; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.stubbing.Answer; - -/** - * A test base providing utility methods to mock environment to run commands test. - */ -@Slf4j -@SuppressWarnings("unchecked") -public abstract class MockCommandSupport { - - private Map> miscMockedConstructions = new HashMap<>(); - private Map> miscMockedStatic = new HashMap<>(); - - private static String mockedClassKey(Class clazz) { - return clazz.getName(); - } - - protected MockedStatic mockStatic(Class classToMock, MockSettings settings) { - final String key = mockedClassKey(classToMock); - final MockedStatic prev = miscMockedStatic.remove(key); - if (prev != null) { - prev.close(); - } - final MockedStatic mockedStatic = Mockito.mockStatic(classToMock, settings); - miscMockedStatic.put(key, mockedStatic); - return mockedStatic; - } - - protected MockedStatic mockStatic(Class classToMock, Answer defaultAnswer) { - return mockStatic(classToMock, withSettings().defaultAnswer(defaultAnswer)); - - } - - protected MockedStatic mockStatic(Class classToMock) { - return mockStatic(classToMock, withSettings()); - } - - protected MockedStatic unsafeGetMockedStatic(Class mockedClass) { - return (MockedStatic) miscMockedStatic.get(mockedClassKey(mockedClass)); - } - - protected MockedStatic getMockedStatic(Class mockedClass) { - final MockedStatic mockedStatic = (MockedStatic) - miscMockedStatic.get(mockedClassKey(mockedClass)); - if (mockedStatic == null) { - throw new RuntimeException("Cannot get mocked static for class " - + mockedClass.getName() + ", not mocked yet."); - } - return mockedStatic; - } - - protected MockedConstruction mockConstruction(Class classToMock) { - return mockConstruction(classToMock, (mocked, context) -> {}); - } - - protected MockedConstruction mockConstruction(Class classToMock, - MockedConstruction.MockInitializer initializer) { - return mockConstruction(classToMock, withSettings(), initializer); - } - - - protected MockedConstruction mockConstruction(Class classToMock, - MockSettings settings, - MockedConstruction.MockInitializer initializer) { - final String key = mockedClassKey(classToMock); - final MockedConstruction prev = miscMockedConstructions.remove(key); - if (prev != null) { - prev.close(); - } - - final MockedConstruction mockedConstruction = Mockito.mockConstruction(classToMock, settings, initializer); - miscMockedConstructions.put(key, mockedConstruction); - return mockedConstruction; - } - - protected MockedConstruction getMockedConstruction(Class mockedClass) { - - final MockedConstruction mockedConstruction = (MockedConstruction) - miscMockedConstructions.get(mockedClassKey(mockedClass)); - if (mockedConstruction == null) { - throw new RuntimeException("Cannot get mocked construction for class " - + mockedClass.getName() + ", not mocked yet."); - } - return mockedConstruction; - } - - - - @After - public void afterMethod() { - miscMockedStatic.values().forEach(MockedStatic::close); - miscMockedStatic.clear(); - - miscMockedConstructions.values().forEach(MockedConstruction::close); - miscMockedConstructions.clear(); - } - -}