/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.artemis.tests.unit.core.paging.impl; import java.nio.ByteBuffer; import java.util.List; import org.apache.activemq.artemis.api.core.ICoreMessage; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.message.impl.CoreMessage; import org.apache.activemq.artemis.core.message.impl.CoreMessagePersister; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.impl.Page; import org.apache.activemq.artemis.core.paging.impl.PagedMessageImpl; import org.apache.activemq.artemis.core.persistence.impl.nullpm.NullStorageManager; import org.apache.activemq.artemis.core.protocol.core.impl.CoreProtocolManagerFactory; import org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessagePersister; import org.apache.activemq.artemis.spi.core.protocol.MessagePersister; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class PageTest extends ActiveMQTestBase { // Constants ----------------------------------------------------- // Attributes ---------------------------------------------------- // Static -------------------------------------------------------- // Constructors -------------------------------------------------- // Public -------------------------------------------------------- @Before public void registerProtocols() { MessagePersister.registerPersister(CoreProtocolManagerFactory.ID, CoreMessagePersister.getInstance()); MessagePersister.registerPersister((byte)2, AMQPMessagePersister.getInstance()); } @Test public void testPageWithNIO() throws Exception { recreateDirectory(getTestDir()); testAdd(new NIOSequentialFileFactory(getTestDirfile(), 1), 1000); } @Test public void testDamagedDataWithNIO() throws Exception { recreateDirectory(getTestDir()); testDamagedPage(new NIOSequentialFileFactory(getTestDirfile(), 1), 1000); } @Test public void testPageFakeWithoutCallbacks() throws Exception { testAdd(new FakeSequentialFileFactory(1, false), 10); } @Test public void testAddCore() throws Exception { testAdd(new NIOSequentialFileFactory(getTestDirfile(), 1), 1); } /** * Validate if everything we add is recovered */ @Test public void testDamagedPage() throws Exception { testDamagedPage(new FakeSequentialFileFactory(1, false), 100); } /** * Validate if everything we add is recovered */ protected void testAdd(final SequentialFileFactory factory, final int numberOfElements) throws Exception { SequentialFile file = factory.createSequentialFile("00010.page"); Page impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); Assert.assertEquals(10, impl.getPageId()); impl.open(); Assert.assertEquals(1, factory.listFiles("page").size()); SimpleString simpleDestination = new SimpleString("Test"); addPageElements(simpleDestination, impl, numberOfElements); impl.sync(); impl.close(); file = factory.createSequentialFile("00010.page"); file.open(); impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); List<PagedMessage> msgs = impl.read(new NullStorageManager()); Assert.assertEquals(numberOfElements, msgs.size()); Assert.assertEquals(numberOfElements, impl.getNumberOfMessages()); for (int i = 0; i < msgs.size(); i++) { Assert.assertEquals(simpleDestination, msgs.get(i).getMessage().getAddressSimpleString()); } impl.delete(null); Assert.assertEquals(0, factory.listFiles(".page").size()); } protected void testDamagedPage(final SequentialFileFactory factory, final int numberOfElements) throws Exception { SequentialFile file = factory.createSequentialFile("00010.page"); Page impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); Assert.assertEquals(10, impl.getPageId()); impl.open(); Assert.assertEquals(1, factory.listFiles("page").size()); SimpleString simpleDestination = new SimpleString("Test"); addPageElements(simpleDestination, impl, numberOfElements); impl.sync(); long positionA = file.position(); // Add one record that will be damaged addPageElements(simpleDestination, impl, 1); long positionB = file.position(); // Add more 10 as they will need to be ignored addPageElements(simpleDestination, impl, 10); // Damage data... position the file on the middle between points A and B file.position(positionA + (positionB - positionA) / 2); ByteBuffer buffer = ByteBuffer.allocate((int) (positionB - file.position())); for (int i = 0; i < buffer.capacity(); i++) { buffer.put((byte) 'Z'); } buffer.rewind(); file.writeDirect(buffer, true); impl.close(); file = factory.createSequentialFile("00010.page"); file.open(); impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); List<PagedMessage> msgs = impl.read(new NullStorageManager()); Assert.assertEquals(numberOfElements, msgs.size()); Assert.assertEquals(numberOfElements, impl.getNumberOfMessages()); for (int i = 0; i < msgs.size(); i++) { Assert.assertEquals(simpleDestination, msgs.get(i).getMessage().getAddressSimpleString()); } impl.delete(null); Assert.assertEquals(0, factory.listFiles("page").size()); Assert.assertEquals(1, factory.listFiles("invalidPage").size()); } /** * @param simpleDestination * @param page * @param numberOfElements * @return * @throws Exception */ protected void addPageElements(final SimpleString simpleDestination, final Page page, final int numberOfElements) throws Exception { int initialNumberOfMessages = page.getNumberOfMessages(); for (int i = 0; i < numberOfElements; i++) { ICoreMessage msg = new CoreMessage().initBuffer(100); for (int j = 0; j < 10; j++) { msg.getBodyBuffer().writeByte((byte) 'b'); } msg.setAddress(simpleDestination); page.write(new PagedMessageImpl(msg, new long[0])); Assert.assertEquals(initialNumberOfMessages + i + 1, page.getNumberOfMessages()); } } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- }