/* * Copyright 2011 Peter Lawrey * * 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 vanilla.java.chronicle.impl; import org.helios.apmrouter.unsafe.UnsafeAdapter; import sun.misc.Unsafe; import sun.nio.ch.DirectBuffer; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Date; /** * @author peter.lawrey */ public class UnsafeExcerpt<C extends DirectChronicle> extends AbstractExcerpt<C> { /** The address of the current excerpt */ long address = -1; protected UnsafeExcerpt(C chronicle) { super(chronicle); } protected void index0(long index, long startPosition, long endPosition) { this.index = index; this.startPosition = startPosition; buffer = chronicle.acquireDataBuffer(startPosition); address = ((DirectBuffer) buffer).address(); start = position = address + chronicle.positionInBuffer(startPosition); limit = address + chronicle.positionInBuffer(endPosition - 1) + 1; assert limit > start && position < limit && endPosition > startPosition; } /** * Rolls the bytes in this excerpt to the right * @param startingPosition The starting position of the roll * @param rightBytes The number of bytes to the right the slots should be rolled * @param bytesToMove The number of bytes to roll */ public void insertAndRollRight(long startingPosition, long rightBytes, long bytesToMove) { long address = ((DirectBuffer) buffer).address(); UNSAFE.copyMemory(address + startingPosition, address + startingPosition + rightBytes, bytesToMove); } // public long[] insertNewPeriod(int entrySize, int size, int offset, long...values) { // try { // LongSlidingWindow sw = new LongSlidingWindow(size*entrySize, readLongArray(offset, size*entrySize)); // //sw.insert(readLongArray(offset, size*5)); // long[] retValues = new long[entrySize]; // for(int i = 0; i < retValues.length; i++) { // retValues[i] = sw.insert(values[i]); // } // writeLongArray(offset, sw.asLongArray()); // sw.destroy(); // return retValues; // } catch (Exception ex) { // ex.printStackTrace(System.err); // return null; // } // } // insertNewPeriod( // SERIES_SIZE_IN_LONGS, // rollSize, // HEADER_OFFSET, // new long[]{period, Long.MAX_VALUE,Long.MIN_VALUE,0,0}); /** * Inserts a new period at the beginning of the series, rolling the existing series to the right * @param incPos If true, the position is incremented * @param entrySize The number of longs being inserted * @param size The number of periods to roll, which is used to calculate the number of bytes to roll * @param offset The relative offset from which the bytes are rolled * @param values The new values to be written into the newly created period * @return the array of values in the first period that were rolled into the next period */ public long[] insertNewPeriod(boolean incPos, int entrySize, int size, int offset, long...values) { final long bytesToRoll = (size * entrySize) << 3; // log(String.format("INS NEW PER:btr:%s/inc:%s/es:%s/sz:%s/off:%s/data:%s", bytesToRoll, incPos, entrySize, size, offset, r(values))); // log(String.format("BUFFER:st:%s/pos:%s/sp:%s/lim:%s-->%s", start, position, startPosition, limit, limit-start)); long[] retVal = readLongArray(offset, entrySize); long _address = start; // log("ROLLING\n\t\t" + r(readLongArray(offset, entrySize)) + "\n\t\tTo:" + r(readLongArray(offset + (entrySize << 3), entrySize))); UNSAFE.copyMemory(_address + offset, _address + offset + (entrySize << 3), bytesToRoll); // log("\n\tBYTES COPIED:" + bytesToRoll + "\n\tROLLED\n\t\t" + r(readLongArray(offset + (entrySize << 3), entrySize))); writeLongArray(offset, values); if(incPos) { position += (entrySize << 3); // log("\n\tINC POS: [" + (entrySize << 3) + "] ---> [" + position + "]"); } return retVal; } protected static void log(Object msg) { System.out.println(msg); System.out.flush(); } /** * Utility method to render a period value array to a readable string * @param values The period values * @return A formatted string */ protected static String r(long[] values) { StringBuilder b = new StringBuilder("Period Values:"); if(values==null) { b.append("null"); } else { if(values.length!=5) { b.append("Invalid Size:").append(Arrays.toString(values)); } else { b.append(new Date(values[0])).append("["); for(int i = 1; i < 5; i++) { b.append(values[i]).append(","); } b.deleteCharAt(b.length()-1); b.append("]"); } } return b.toString(); } /** * Rolls the bytes in this excerpt to the right starting at position zero * @param rightBytes The number of bytes to the right the slots should be rolled * @param slotsToMove The number of bytes to roll */ public void insertAndRollRight(long rightBytes, long slotsToMove) { insertAndRollRight(0, rightBytes, slotsToMove); } // RandomDataInput @Override public byte readByte() { return UNSAFE.getByte(position++); } @Override public byte readByte(int offset) { return UNSAFE.getByte(start + offset); } @Override public void write(int offset, byte[] b) { UnsafeAdapter.copyMemory(b, BYTES_OFFSET, null, position, b.length); position += b.length; } @Override public void write(byte[] b, int off, int len) { UnsafeAdapter.copyMemory(b, BYTES_OFFSET + off, null, position, len); position += len; } @Override public void readFully(byte[] b, int off, int len) { UnsafeAdapter.copyMemory(null, position, b, BYTES_OFFSET + off, len); position += len; } @Override public short readShort() { short s = UNSAFE.getShort(position); position += 2; return s; } @Override public short readShort(int offset) { return UNSAFE.getShort(start + offset); } @Override public char readChar() { char ch = UNSAFE.getChar(position); position += 2; return ch; } @Override public char readChar(int offset) { return UNSAFE.getChar(start + offset); } @Override public int readInt() { int i = UNSAFE.getInt(position); position += 4; return i; } @Override public int readInt(int offset) { return UNSAFE.getInt(start + offset); } @Override public long readLong() { long l = UNSAFE.getLong(position); position += 8; return l; } /** * Reads and returns a long array from the excerpt * @param offset The offset in the excerpt to read from * @param length The length of the long array to read * @return the read array */ public long[] readLongArray(int offset, int length) { long[] arr = new long[length]; UNSAFE.copyMemory(null, start + offset, arr, LONGS_OFFSET, length << 3); return arr; } /** * Reads and returns a long array from the excerpt * @param length The length of the long array to read * @return the read array */ public long[] readLongArray(int length) { long[] arr = new long[length]; UNSAFE.copyMemory(null, position, arr, LONGS_OFFSET, length << 3); return arr; } /** * Writes a long array to the specified offset in this excerpt * @param offset The offset to write at * @param arr The array to write */ public void writeLongArray(int offset, long...arr) { UNSAFE.copyMemory(arr, LONGS_OFFSET, null, start + offset, arr.length << 3); } /** * Writes a long array to the current position * @param arr The array to write */ public void writeLongArray(long...arr) { UNSAFE.copyMemory(arr, LONGS_OFFSET, null, position, arr.length << 3); position += arr.length << 3; } @Override public long readLong(int offset) { return UNSAFE.getLong(start + offset); } @Override public float readFloat() { float f = UNSAFE.getFloat(position); position += 4; return f; } @Override public float readFloat(int offset) { return UNSAFE.getFloat(start + offset); } @Override public double readDouble() { double d = UNSAFE.getDouble(position); position += 8; return d; } @Override public double readDouble(int offset) { return UNSAFE.getDouble(start + offset); } @Override public void write(int b) { UNSAFE.putByte(position++, (byte) b); } @Override public void write(int offset, int b) { UNSAFE.putByte(start + offset, (byte) b); } @Override public void writeShort(int v) { UNSAFE.putShort(position, (short) v); position += 2; } @Override public void writeShort(int offset, int v) { UNSAFE.putShort(start + offset, (short) v); } @Override public void writeChar(int v) { UNSAFE.putChar(position, (char) v); position += 2; } @Override public void writeChar(int offset, int v) { UNSAFE.putChar(start + offset, (char) v); } @Override public void writeInt(int v) { UNSAFE.putInt(position, v); position += 4; } @Override public void writeInt(int offset, int v) { UNSAFE.putInt(start + offset, v); } @Override public void writeLong(long v) { UNSAFE.putLong(position, v); position += 8; } @Override public void writeLong(int offset, long v) { UNSAFE.putLong(start + offset, v); } public void writeToken(long token) { buffer.putLong(0, token); UNSAFE.putLong(start, token); } @Override public void writeFloat(float v) { UNSAFE.putFloat(position, v); position += 4; } @Override public void writeFloat(int offset, float v) { UNSAFE.putFloat(start + offset, v); } @Override public void writeDouble(double v) { UNSAFE.putDouble(position, v); position += 8; } @Override public void writeDouble(int offset, double v) { UNSAFE.putDouble(start + offset, v); } /** * *** Access the Unsafe class ***** */ private static final Unsafe UNSAFE; private static final int BYTES_OFFSET; private static final int LONGS_OFFSET; private static final int INTS_OFFSET; static { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); UNSAFE = (Unsafe) theUnsafe.get(null); BYTES_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); LONGS_OFFSET = UNSAFE.arrayBaseOffset(long[].class); INTS_OFFSET = UNSAFE.arrayBaseOffset(int[].class); } catch (Exception e) { throw new AssertionError(e); } } }