/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS 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.extras.benchmarks.journal.gcfree;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.apache.activemq.artemis.core.io.SequentialFile;
import org.apache.activemq.artemis.core.io.SequentialFileFactory;
import org.apache.activemq.artemis.core.journal.impl.JournalFile;
import org.apache.activemq.artemis.core.journal.impl.JournalImpl;
final class GcFreeJournal extends JournalImpl {
private final AddJournalRecordEncoder addJournalRecordEncoder = new AddJournalRecordEncoder();
//TODO replace with thread local pools if not single threaded!
private ByteBuffer journalRecordBytes = null;
GcFreeJournal(final int fileSize,
final int minFiles,
final int poolSize,
final int compactMinFiles,
final int compactPercentage,
final SequentialFileFactory fileFactory,
final String filePrefix,
final String fileExtension,
final int maxAIO) {
super(fileSize, minFiles, poolSize, compactMinFiles, compactPercentage, fileFactory, filePrefix, fileExtension, maxAIO, 0);
}
public static int align(final int value, final int alignment) {
return (value + (alignment - 1)) & ~(alignment - 1);
}
public void appendAddRecord(final long id,
final int recordType,
final ByteBuffer encodedRecord,
final int offset,
final int length,
final boolean sync) throws Exception {
final int expectedLength = JournalRecordHeader.BYTES + AddJournalRecordEncoder.expectedSize(length);
final int alignedLength = align(expectedLength, 8);
switchFileIfNecessary(alignedLength);
final JournalFile currentFile = getCurrentFile();
final int fileId = currentFile.getRecordID();
if (this.journalRecordBytes == null || this.journalRecordBytes.capacity() < alignedLength) {
final int newPooledLength = align(alignedLength, 4096);
//TODO ADD LIMITS OR WARNS IN CASE OF TOO MUCH BIGGER SIZE
this.journalRecordBytes = ByteBuffer.allocateDirect(newPooledLength);
this.journalRecordBytes.order(ByteOrder.nativeOrder());
}
final long journalRecordHeader = JournalRecordHeader.makeHeader(JournalRecordTypes.ADD_JOURNAL, expectedLength);
this.journalRecordBytes.putLong(0, journalRecordHeader);
//use natural stride while encoding: FileId<CompactCount<Id<RecordType<RecordBytes
this.addJournalRecordEncoder.on(this.journalRecordBytes, JournalRecordHeader.BYTES).fileId(fileId).compactCount(0).id(id).recordType(recordType).record(encodedRecord, offset, length);
final SequentialFile sequentialFile = currentFile.getFile();
try {
this.journalRecordBytes.limit(alignedLength);
sequentialFile.writeDirect(this.journalRecordBytes, sync);
} finally {
this.journalRecordBytes.clear();
}
//TODO AVOID INDEXING WITH CONCURRENT MAP!
}
}