package org.csc.phynixx.loggersystem.logrecord; /* * #%L * phynixx-connection * %% * Copyright (C) 2014 csc * %% * 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. * #L% */ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.csc.phynixx.common.TestUtils; import org.csc.phynixx.common.TmpDirectory; import org.csc.phynixx.common.io.LogRecordPageReader; import org.csc.phynixx.common.io.LogRecordPageWriter; import org.csc.phynixx.common.logger.IPhynixxLogger; import org.csc.phynixx.common.logger.PhynixxLogManager; import org.csc.phynixx.loggersystem.logger.IDataLoggerFactory; import org.csc.phynixx.loggersystem.logger.channellogger.FileChannelDataLoggerFactory; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * test the mult threading capabilities of phynixx logger * * phynixx logger aren't multi thread safe. The calling environment has to separet the different logger or has to take that they are synchronized. */ public class MTXAResourceLoggerTest { public static final int NUM_THREADS = 10; private IPhynixxLogger log = PhynixxLogManager.getLogger(this.getClass()); private TmpDirectory tmpDir = null; private final String MT_MESSAGE = "1234567890qwertzui"; @Before public void setUp() throws Exception { // configuring the log-system (e.g. log4j) TestUtils.configureLogging(); // delete all tmp files ... this.tmpDir = new TmpDirectory("test"); this.tmpDir.clear(); this.tmpDir = new TmpDirectory("test"); System.getProperties().setProperty("howl.log.logFileDir", this.tmpDir.getDirectory().getCanonicalPath()); } @After public void tearDown() throws Exception { // delete all tmp files ... this.tmpDir.clear(); } @Test public void testMTLogging() throws Exception { // Start XALogger .... IDataLoggerFactory loggerFactory = new FileChannelDataLoggerFactory("mt", this.tmpDir.getDirectory()); PhynixxXARecorderRepository repository= new PhynixxXARecorderRepository(loggerFactory); try { // Start Threads to fill the Logs. List<Thread> workers = new ArrayList<Thread>(); for (int i = 0; i < NUM_THREADS; i++) { MessageSampler sampler = new MessageSampler(i, repository, MT_MESSAGE, (10 % (i + 1) + 2)); Thread worker = new Thread(sampler); worker.start(); workers.add(worker); } // wait until all threads are ready .. for (int i = 0; i < workers.size(); i++) { Thread worker = workers.get(i); worker.join(); } } finally { } repository.close(); IXARecorderRecovery recorderRecovery=null; try { recorderRecovery = new XARecorderRecovery(loggerFactory); Set<IXADataRecorder> dataRecorders = recorderRecovery.getRecoveredXADataRecorders(); Assert.assertEquals(NUM_THREADS, dataRecorders.size()); log.info(dataRecorders.toString()); for (IXADataRecorder dataRecorder : dataRecorders) { final List<IDataRecord> records = dataRecorder.getDataRecords(); MessageReplay replay = new MessageReplay(); for (int i = 0; i < records.size(); i++) { replay.replayRollback(records.get(i)); } replay.check(); } } finally { recorderRecovery.close(); } } private static class MessageReplay implements IDataRecordReplay { private String content = null; private StringBuffer contentParts = new StringBuffer(); @Override public void notifyNoMoreData() { } @Override public void replayRollback(IDataRecord message) { String value=null; try { value = new LogRecordPageReader(message.getData()).getLogReaders().get(0).readUTF(); } catch (IOException e) { e.printStackTrace(); } if (message.getOrdinal().intValue() == 1) { this.content= value; } else { String part =value; contentParts.append(part); } } @Override public void replayRollforward(IDataRecord message) { } public void check() { if (!content.equals(contentParts.toString())) { throw new IllegalStateException("content=" + content + " parts=" + contentParts.toString()); } } } private class MessageSampler implements Runnable { private String message = null; private int chunkSize; private IXADataRecorder dataRecorder; private MessageSampler(int index,IXARecorderRepository repository, String message, int chunkSize) throws Exception { this.dataRecorder = repository.createXADataRecorder(); this.message = message; this.chunkSize = chunkSize; this.dataRecorder.createDataRecord(XALogRecordType.USER, new LogRecordPageWriter().newLine().writeUTF(message).toByteArray()); } public String getMessage() { return message; } public int getChunkSize() { return chunkSize; } @Override public void run() { // sample the Message int countChunks = (message.length() / chunkSize); if (message.length() % chunkSize != 0) { countChunks++; } log.info("ChunkSize="+this.chunkSize+" ChunkCount="+countChunks+" MessageLength="+message.length()); try { for (int i = 0; i < countChunks; i++) { if(i*chunkSize < message.length()) { String messageChunk = message.substring(i * chunkSize, Math.min((i + 1) * chunkSize, message.length())); this.dataRecorder.createDataRecord(XALogRecordType.USER, new LogRecordPageWriter().newLine().writeUTF(messageChunk).toByteArray()); } } } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } } } }